home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.1_SDK_DR3 / Source / FWiX / FWiXApp / FWiXmain.c < prev    next >
Encoding:
Text File  |  1999-05-17  |  90.4 KB  |  3,662 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FWiXMain.c
  3.  
  4.     Contains:    Application software to transfer files over FireWire.
  5.  
  6.     Version:    1.0
  7.  
  8.     Written by:    Jay Lloyd
  9.     
  10.     Copyright:    © 1996-1999 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     File Ownership:
  13.  
  14.         DRI:                Jay Lloyd
  15.  
  16.         Other Contact:        
  17.  
  18.         Technology:            FireWire
  19.  
  20.     Writers:
  21.  
  22.         (DCB)    Clinton Bauder
  23.         (jkl)    Jay Lloyd
  24.  
  25.     Change History (most recent first):
  26.  
  27.       <FW38>      4/8/99    jkl        More interface cleanup.
  28.       <FW37>      2/2/99    DCB        Fix for latest MI headers.
  29.       <FW36>    12/19/98    DCB        More cleanup for SDK.
  30.       <FW35>     7/24/98    jkl        Removed page alignment of data buffers.
  31.       <FW34>     7/22/98    jkl        Call CreateMenus before InitPrefs. InitPrefs tries to adjust a
  32.                                     menu item name.
  33.         <33>     1/15/98    jkl        Update for new headers.
  34.       <FW32>     6/19/97    jkl        Added support for GetNodeList and SendItems AppleScript
  35.                                     commands. Saved the icons view as a preference. Updated the open
  36.                                     sharing setup command for Tempo to open File Sharing .
  37.       <FW31>     6/10/97    jkl        Made sure a device added message does not result in the same
  38.                                     device getting added twice.
  39.       <FW30>     5/28/97    jkl        Made sure send or receive error is cleared before calling error
  40.                                     dialog. The not cleared error could cause the dialog to
  41.                                     repeatedly display itself.
  42.       <FW29>     5/27/97    jkl        Changed memory allocation for data buffers to ensure they are on
  43.                                     4k boundaries.
  44.       <FW28>     5/16/97    jkl        Corrected some GetPort SetPort bracketing around updates and
  45.                                     drawing.
  46.       <FW27>     5/15/97    jkl        Modified error handling routines to recover from errors during
  47.                                     the transfer check before file sending has started. Held all of
  48.                                     the completion routines.
  49.       <FW26>      5/7/97    jkl        Modified linked lists to double linked lists to simplify
  50.                                     insertion and deletion of list items.
  51.       <FW25>     4/29/97    jkl        Fixed main symbol export. Made sure drop folder exsists before
  52.                                     calling open drop folder routine.
  53.       <FW24>     4/29/97    jkl        Added global alert routine to handle alert event filters.
  54.                                     Corrected a problem that could leave the connected fwix machine
  55.                                     list corrupted.
  56.       <FW23>      4/8/97    jkl        Added page up/down, home, and end key scrolling support. Changed
  57.                                     my BBS initials to not conflict with Jim Luther's.
  58.       <FW22>     3/18/97    jkl        Added new icons. Changed text drawing to use TETextBox. Moved
  59.                                     prefs related routines to prefs.c.
  60.       <FW21>     2/27/97    jkl        Modified preferences to be under receiver control and removed
  61.                                     prompt preference. Added Edit menu and moved Preferences command
  62.                                     to there. Added support for scrolling the sender window.
  63.       <FW20>     2/21/97    jkl        Changed icon placement and management in sender window for
  64.                                     better multiple node support. Updated preferences menu to handle
  65.                                     menus and sound popup correctly.
  66.       <FW19>     2/19/97    jkl        Added Reply/Request options to SendFWXInfo. Set the state of the
  67.                                     sound notification popup menu according to the play sound check
  68.                                     box. Added play the sound after it is selected in the popup.
  69.                                     Corrected window zoom states. Made sure notification resources
  70.                                     are not purgeable.
  71.       <FW18>     2/13/97    jkl        Added a ForkWriteComplete to make sure a data buffer is
  72.                                     available before starting to read a new file fork.
  73.       <FW17>     2/11/97    jkl        Added read control and read data buffers and queues. Moved fwix
  74.                                     preferences to a file and closed file in all cases. Fixed
  75.                                     buttons in no sharing name dialog.
  76.       <FW16>     2/10/97    ES        Cleaned up deallocation code. Removed system heap allocations.
  77.       <FW15>      2/7/97    ES        Added call to GetNextFWXClientEvent in event loop.
  78.       <FW14>      2/6/97    ES        Changed to maintain list of all nodes that have been opened.
  79.                                     Will send quit notification to and close all nodes that have
  80.                                     been opened when quitting.
  81.       <FW13>      2/5/97    ES        Changed a CloseFWXDriver to CloseFWXNode.
  82.       <FW12>      2/2/97    jkl        Added Open Sharing Setup command to no machine name alert.
  83.                                     Modified menus and corrected menu state enabled/disabled
  84.                                     problems. Changed open drop folder command to make the finder
  85.                                     the foreground process. Corrected view size menu commands to
  86.                                     only work if that size is not the current size. Move the
  87.                                     preferences to a file. Correct the flahsing icon notification.
  88.                                     Moved NewPtrSys calls that are safe back to NewPtr.
  89.       <FW11>     1/29/97    ES        Changed InstallCompletionRoutineProcs to set up completion
  90.                                     routines to return status in D0. This is a workaround for a bug
  91.                                     in the File Manager.
  92.       <FW10>     1/27/97    ES        Added creation of FWControl PB queue.
  93.        <FW9>     1/27/97    jkl        Added timer routines to check for transfer disconnects and
  94.                                     errors. At idle check for timeout errors. Cleaned up from a
  95.                                     device removed event properly if a transfer is in progress.
  96.                                     Removed killio routine from CloseWindow, will let closing the
  97.                                     node handle it. Added check for transmit in progress and option
  98.                                     to quit or continue. Fixed stop button in progress dialog by
  99.                                     adding setport call. Modified view options menu to show check
  100.                                     marks instead of toggle title.
  101.        <FW8>     1/17/97    ES        Changed a CallFWXDriver to CallFWXNode. Changed NewPtrs to
  102.                                     NewPtrSyss because some buffers need to be held to be VM safe;
  103.                                     this is overkill, and really we just need to hold the right
  104.                                     buffers. Used NewPtrSysClear to allocate pRecvNode so that its
  105.                                     next pointer is nil.
  106.        <FW7>     1/16/97    jkl        Removed an open DebugStr call.
  107.        <FW6>     1/16/97    jkl        Added user interface features for alpha candidate. Added a
  108.                                     preferences dialog, changed window behavior to match normal
  109.                                     window behavior, changed fwix node icons to only be displayed if
  110.                                     the node has fwix running. Added receive file notification.
  111.        <FW5>      1/8/97    ES        Changed to use FWX nodes instead of FWX drivers. Fixed up hot
  112.                                     plugging and unplugging.
  113.        <FW4>    11/13/96    jkl        Moved from DoDriverIO interface to CallDriver. Implemented stop
  114.                                     transfer. Now Indentify receivers by name.
  115.        <FW3>     10/31/96    jkl        Fixed event handling when copy progress dialog
  116.                                        is being displayed. Added routine to update copy
  117.                                     progress dialog at idle time. Moved receive folder
  118.                                     check and initialization to application init time.
  119.        <FW2>     10/16/96    jkl        Modified queue handling to use OS Utils interrupt
  120.                                        safe queue routines. Created File Write Completion
  121.                                     routine proc. Removed reads and writes from idle
  122.                                     handler. The idle handler only checks to see if
  123.                                     the read or write is done. The reads and writes
  124.                                     are continued in the various completion routines.
  125.        <FW1>     10/2/96    jkl        Initial check-in.
  126. */
  127.  
  128. #include <QuickDraw.h>
  129. #include <SegLoad.h>
  130. #include <Types.h>
  131. #include <Memory.h>
  132. #include <Resources.h>
  133. #include <Fonts.h>
  134. #include <Controls.h>
  135. #if !ETO_Build
  136. #include <ControlDefinitions.h>
  137. #endif
  138. #include <Menus.h>
  139. #include <Dialogs.h>
  140. #include <Events.h>
  141. #include <AppleEvents.h>
  142. #include <Processes.h>
  143. #include <Windows.h>
  144. #include <Errors.h>
  145. #include <Files.h>
  146. #include <Folders.h>
  147. #include <Script.h>
  148. #include <Devices.h>
  149. #include <TextUtils.h>
  150. #include <ToolUtils.h>
  151. #include <StandardFile.h>
  152. #include <Icons.h>
  153. #include <DiskInit.h>    
  154. #include <Notification.h>
  155. #include <Timer.h>
  156. #include <Sound.h>
  157.  
  158. #include "FWiX.h"
  159.  
  160. #include "FWiXmain.h"
  161. #include "FWiXdrag.h"
  162.  
  163. #include <stdio.h>
  164. char  debugStr[256];
  165. static pascal void FWDebugStr(
  166.     ConstStr255Param            debuggerMsg)
  167. {
  168. #ifdef FW_DEBUG_BUILD
  169. #if FW_DEBUG_BUILD
  170.     DebugStr (debuggerMsg);
  171. #endif
  172. #endif
  173. }
  174.  
  175. //////////////////////////////////////////////////////////////////////////////
  176. //
  177. // Internal procedure prototypes.
  178. //
  179.  
  180. static OSErr SendDeviceAddedToSelf (
  181.     FWXNodeID                theNodeID);
  182.  
  183. static OSErr SendDeviceRemovedToSelf (
  184.     FWXNodeID                theNodeID);
  185.     
  186. static pascal OSErr    HandleDeviceAddedEvent (
  187.     AppleEvent                *theAppleEvent,
  188.     AppleEvent                *reply,
  189.     SInt32                    handlerRefcon);
  190.  
  191. static OpenNodePtr GetNodeInfoFromID (
  192.     FWXNodeID                nodeID);
  193.  
  194. static pascal OSErr    HandleDeviceRemovedEvent (
  195.     AppleEvent                *theAppleEvent,
  196.     AppleEvent                *reply,
  197.     SInt32                    handlerRefcon);
  198.     
  199. void AdjustNodeIcons (
  200.     WindowDataPtr            pWinData,
  201.     Rect                    *windRect);
  202.  
  203. OSErr SendFWXInfo (
  204.     FWXNodeID                nodeID,
  205.     UInt32                    sendType);
  206.  
  207. OSErr SendFWXQuit (void);
  208.  
  209. static OSErr SetupFWXRead (
  210.     FWXNodeID                nodeID);
  211.  
  212. static OSErr GetNodeIDFromEvent (
  213.     AppleEvent                *pEvent,
  214.     FWXNodeID                *nodeID);
  215.     
  216. static OSErr GetNodeIDFromName (
  217.     FWXNodeID                *nodeID,
  218.     ConstStr255Param        nodeName);
  219.  
  220. static OSErr NewSenderWindow (void);
  221.  
  222. static void GetDisplayRect (
  223.     Rect                    *r,
  224.     WindowPtr                pWin,
  225.     WindowDataPtr            pWinData);
  226.  
  227. OSErr AdjustScrollBars (
  228.     WindowPtr                pWin,
  229.     Boolean                    adjustSizes);
  230.  
  231. OSErr InitRecvNode (
  232.     FWXNodeID                nodeID,
  233.     ConstStr255Param        nodeName);
  234.     
  235. static pascal void HandleReplyTimeout (
  236.     MyTMTaskPtr            pTMTask);
  237.  
  238. static pascal OSErr HandleGetNodeListEvent (
  239.     AppleEvent                *pAppleEvent,
  240.     AppleEvent                *pReplyEvent,
  241.     SInt32                    refCon);
  242.  
  243. static pascal OSErr HandleSendItemsEvent (
  244.     AppleEvent                *pAppleEvent,
  245.     AppleEvent                *pReplyEvent,
  246.     SInt32                    refCon);
  247.     
  248. static OSErr GetFSItemsFromEvent (
  249.     FSSpecPtr                *pSendItems,
  250.     AppleEvent                *pEvent,
  251.     UInt16                    *numItems);
  252.  
  253. static OSErr GetReceiveNodesFromEvent (
  254.     FWXNodeID                **pReceiveNodeIDList,
  255.     AppleEvent                *pAppleEvent,
  256.     UInt16                    *numNodes);
  257.     
  258. static pascal OSErr HandleOpenApplicationEvent (
  259.     AppleEvent                *pAppleEvent,
  260.     AppleEvent                *pReplyEvent,
  261.     SInt32                    refCon);
  262.     
  263. static pascal OSErr HandleOpenDocumentsEvent (
  264.     AppleEvent                *pAppleEvent,
  265.     AppleEvent                *pReplyEvent,
  266.     SInt32                    refCon);
  267.     
  268. static pascal OSErr HandleQuitApplicationEvent (
  269.     AppleEvent                *pAppleEvent,
  270.     AppleEvent                *pReplyEvent,
  271.     SInt32                    refCon);
  272.     
  273. static OSErr InstallAppleEventHandlers (void);
  274.  
  275. static OSErr InstallCompletionRoutineProcs (void);
  276.  
  277. static void DrawWindow (
  278.     WindowPtr                pWin);
  279.  
  280. static OSErr CreateMenus (void);
  281.  
  282. static void HandleCloseWindow (
  283.     WindowPtr                pWin);
  284.     
  285. static void HandleQuit (void);
  286.  
  287. static void HandleMenuCommand (
  288.     SInt32                    menuVal);
  289.     
  290. OSErr OpenDropFolder(void);
  291.  
  292. static OSErr OpenSharingSetup(void);
  293.  
  294. static OSErr HandleViewSize(
  295.     SInt16                    menuItem);
  296.  
  297. static void HandleMouseDownEvent (
  298.     EventRecord                *pEventRecord);
  299.  
  300. static pascal void HandleThumbScroll (
  301.     ControlHandle            scrollCtl,
  302.     WindowPtr                pWin,
  303.     Point                    mouse);
  304.  
  305. static pascal void HandleScrollAction (
  306.     ControlHandle            scrollCtl,
  307.     SInt16                    part);
  308.  
  309. static void HandleGrowWindow(
  310.     WindowPtr                    pWin,
  311.     Point                        clickLoc);
  312.  
  313. static void HandleZoomWindow(
  314.     WindowPtr                    pWin,
  315.     SInt16                        whichZoom);
  316.  
  317. void StopTransfer (
  318.     RecvNodePtr                    pNode);
  319.  
  320. static void HandleKeyEvent (
  321.     EventRecord                *pEventRecord);
  322.  
  323. static void HandleOSEvent (
  324.     EventRecord                *pEventRecord);
  325.  
  326. static void HandleEvent (
  327.     EventRecord                *theEvent);
  328.  
  329. static void HandleActivate (
  330.     WindowPtr                pWin,
  331.     Boolean                    becomingActive);
  332.  
  333. static Boolean IsAppWindow (
  334.     WindowPtr                pWin);
  335.     
  336. static pascal Boolean HandleAlertEventFilter (
  337.     DialogPtr                pDlog,
  338.     EventRecord                *pEvent,
  339.     SInt16                    *itemHit);
  340.  
  341. static OSErr SetupFWXNode (void);
  342.  
  343. static OSErr InitNotification (void);
  344.  
  345. pascal void HandleNotifyResponse (
  346.     NMRecPtr                pNMRequest);
  347.  
  348.  
  349. static OSErr SetupIOQueue (void);
  350.  
  351. static OSErr FWXInit (void);
  352.     
  353. static OSErr FWXDispose (void);
  354.  
  355. //////////////////////////////////////////////////////////////////////////////
  356. //
  357. // External procedure prototypes.
  358. //
  359.  
  360. extern OSErr InstallDragHandlers (void);    
  361.  
  362. extern void RemoveDragHandlers (void);
  363.     
  364. extern pascal OSErr HandleAEFileSpecList (
  365.     AppleEvent                *pAEvent,
  366.     AppleEvent                 *pReply,
  367.     SInt32                    refCon);
  368.  
  369. extern OSErr GetNodeDragRect (
  370.     WindowPtr                pWin,
  371.     SInt16                    spaceIndex,
  372.     Rect                    *iconRect,
  373.     Rect                    *textRect);
  374.  
  375. extern void HandleReceive (void);
  376.  
  377. extern void HandleForkReadComplete (void);
  378.  
  379. extern OSErr FSGetCatInfo (
  380.     FSSpec                     *fsSpec,
  381.     CInfoPBPtr                result);
  382.  
  383. extern void UpdateProgressBar (
  384.     WindowPtr            theWindow,
  385.     SInt16                itemNo);
  386.  
  387. extern OSErr GetNodeName (
  388.     WindowPtr            pWin,
  389.     SInt16                spaceIndex,
  390.     StringPtr            *pString);
  391.     
  392. extern void CleanupCopyDialog(
  393.     WindowPtr            theDialog);
  394.  
  395. extern OSErr GetNodeInfo (
  396.     FWXNodeID            nodeID,
  397.     RecvNodePtr            *pRecvNode);
  398.  
  399. extern OSErr HandleStopTransfer(
  400.     CurFileInfoPtr        pCurFileInfo);
  401.     
  402. extern OSErr GetCurFileInfo(
  403.     FWXNodeID            sourceID,
  404.     CurFileInfoPtr        *hCurFileInfo,
  405.     Boolean                createNew);
  406.  
  407. extern OSErr InitRecvFolder(
  408.     SInt32                *dirID);
  409.  
  410.  
  411. //////////////////////////////////////////////////////////////////////////////
  412. //
  413. //    Globals JKL *** these all need to be cleaned up
  414. //
  415. #ifndef __MWERKS__
  416. QDGlobals            qd;
  417. #endif
  418.  
  419. FWXAppDataPtr        gpFWXAppData = nil;
  420.  
  421. Boolean                queuesInitialized = false;
  422. QHdr                gSendQHdr;
  423. QHdr                gAESendQHdr;
  424. QHdr                gReceiveQHdr;
  425. QHdr                gFileReadQHdr;
  426. QHdr                gFWControlQHdr;
  427. QHdr                gFWWriteQHdr;
  428. QHdr                gCurFileQHdr;
  429. SInt16                gCurForkRefNum;
  430.  
  431. Boolean             gSendingFile,
  432.                     gCheckingTransfer,
  433.                     gSendingDataFork,
  434.                     gSendingResFork,
  435.                     gForkWriteComplete,
  436.                     gForkComplete;
  437.  
  438. FWXNodeID    gSendError;
  439. FWXNodeID    gReceiveError;
  440.                     
  441. //////////////////////////////////////////////////////////////////////////////
  442. //
  443. //    SendDeviceAddedToSelf
  444. //
  445. //    Send a firewire device added appleevent to us
  446. //
  447. static OSErr SendDeviceAddedToSelf(
  448.     FWXNodeID                theNodeID)
  449. {
  450.     AppleEvent                send;
  451.     AppleEvent                reply;
  452.     AEDesc                    selfTarget;
  453.     ProcessSerialNumber        psn;
  454.     OSErr                    err;
  455.  
  456.     selfTarget.dataHandle = nil;
  457.     send.dataHandle = nil;
  458.  
  459.     // Get our address
  460.     GetCurrentProcess(&psn);
  461.     err = AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber), &selfTarget);
  462.     if (err != noErr)
  463.         return err;
  464.             
  465.     err = AECreateAppleEvent(kAEFWXEventClass, kAEFWXDeviceAdded, &selfTarget, 
  466.             kAutoGenerateReturnID, kAnyTransactionID, &send);
  467.     if (err != noErr) {
  468.         AEDisposeDesc(&selfTarget);
  469.         return err;
  470.     }
  471.     
  472.     err = AEPutParamPtr(&send, kAEFWXNodeIDKey, kAEFWXNodeIDType, (Ptr) &theNodeID, sizeof(FWXNodeID));
  473.  
  474.     err = AESend(&send, &reply, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  475.                 kAENormalPriority, kAEDefaultTimeout, nil, nil);
  476.  
  477.     if (err != noErr) {
  478.         AEDisposeDesc(&selfTarget);
  479.         AEDisposeDesc(&send);
  480.     }
  481.  
  482.     return err;
  483. }
  484.  
  485. //////////////////////////////////////////////////////////////////////////////
  486. //
  487. //    SendDeviceRemovedToSelf
  488. //
  489. //    Send a firewire device removed appleevent to us
  490. //
  491. static OSErr SendDeviceRemovedToSelf(
  492.     FWXNodeID                theNodeID)
  493. {
  494.     AppleEvent                send;
  495.     AppleEvent                reply;
  496.     AEDesc                    selfTarget;
  497.     ProcessSerialNumber        psn;
  498.     OSErr                    err;
  499.  
  500.     selfTarget.dataHandle = nil;
  501.     send.dataHandle = nil;
  502.  
  503.     // Get our address
  504.     GetCurrentProcess(&psn);
  505.     err = AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber), &selfTarget);
  506.     if (err != noErr)
  507.         return err;
  508.             
  509.     err = AECreateAppleEvent(kAEFWXEventClass, kAEFWXDeviceRemoved, &selfTarget, 
  510.             kAutoGenerateReturnID, kAnyTransactionID, &send);
  511.     if (err != noErr) {
  512.         AEDisposeDesc(&selfTarget);
  513.         return err;
  514.     }
  515.         
  516.     err = AEPutParamPtr(&send, kAEFWXNodeIDKey, kAEFWXNodeIDType, (Ptr) &theNodeID, sizeof(FWXNodeID));
  517.  
  518.     err = AESend(&send, &reply, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  519.                 kAENormalPriority, kAEDefaultTimeout, nil, nil);
  520.  
  521.     if (err != noErr) {
  522.         AEDisposeDesc(&selfTarget);
  523.         AEDisposeDesc(&send);
  524.     }
  525.     
  526.     return err;
  527. }
  528.  
  529. //////////////////////////////////////////////////////////////////////////////
  530. //
  531. //    HandleDeviceAddedEvent
  532. //
  533. //    Called when a new FireWire File Exchange receiver connects to the bus.
  534. //    Add it to the list of open nodes. Prime it with receive buffers. Send our
  535. //    machine info to it.
  536. //
  537. static pascal OSErr    HandleDeviceAddedEvent (
  538.     AppleEvent            *theAppleEvent,
  539.     AppleEvent            *reply,
  540.     long                handlerRefcon)
  541. {
  542.     WindowPtr            pWin;
  543.     WindowDataPtr        pWinData;
  544.     OpenNodePtr            pOpenNode;
  545.     OpenNodePtr            pTempOpenNode;
  546.     FWXNodeID            nodeID;
  547.     OSErr                err = noErr;
  548.     
  549.     //    get node id out of appleevent
  550.     err = GetNodeIDFromEvent(theAppleEvent, &nodeID);
  551.         
  552.     if (err == noErr)
  553.         pOpenNode = GetNodeInfoFromID(nodeID);
  554.     
  555.     if ((err == noErr) && (pOpenNode == nil))
  556.     {
  557.         pWin = gpFWXAppData->pSenderWindow;
  558.         pWinData = (WindowDataPtr) GetWRefCon(pWin);
  559.         if (pWinData == nil)
  560.             err = memFullErr;
  561.         
  562.         if (err == noErr)
  563.         {
  564.             // create open node record.
  565.             pOpenNode = (OpenNodePtr) NewPtrClear(sizeof(OpenNodeRecord));
  566.             if (pOpenNode != nil)
  567.                 pOpenNode->nodeID = nodeID;
  568.             else
  569.                 err = memFullErr;
  570.         }
  571.             
  572.         if (err == noErr)
  573.             // open the node
  574.             err = OpenFWXNode(nodeID);
  575.                 
  576.         if (err == noErr)
  577.         {
  578.             pWinData->numOpenNodes++;
  579.         
  580.             // add the node to the open list
  581.             // if this is the first node, just point to it
  582.             if (pWinData->numOpenNodes == 1)
  583.                 pWinData->pOpenNodeList = pOpenNode;
  584.             else
  585.             {
  586.                 // it is not the first node, traverse the list, add new node to the end
  587.                 pTempOpenNode = pWinData->pOpenNodeList;
  588.                 while (pTempOpenNode->pNextNode != nil)            
  589.                     pTempOpenNode = pTempOpenNode->pNextNode;
  590.                 pTempOpenNode->pNextNode = pOpenNode;
  591.                 pOpenNode->pPreviousNode = pTempOpenNode;
  592.             }
  593.         }
  594.  
  595.         if (err != noErr)
  596.         {
  597.             // clean up on error
  598.             if (pOpenNode != nil)
  599.                 DisposePtr((Ptr) pOpenNode);
  600.         }
  601.  
  602.         if (err == noErr)
  603.             // issue reads to prime node with receive buffers
  604.             err = SetupFWXRead(nodeID);
  605.             
  606.         if (err == noErr)
  607.             // send the new node our name and id info
  608.             err = SendFWXInfo(nodeID, kNodeInfoRequest);
  609.     
  610.         if (err == memFullErr)
  611.             HandleStopAlert(kMemoryErrorAlertID);
  612.         else if (err != noErr)
  613.             // JKL *** need a generic error alert mechanism
  614.             HandleStopAlert(kUnknownErrAlertID);
  615.     }
  616.     return err;
  617. }
  618.  
  619. ////////////////////////////////////////////////////////////////////////////////
  620. //
  621. //    GetNodeInfoFromID
  622. //
  623. //    Search open node list for node record corresponding to node id.
  624. //
  625. static OpenNodePtr GetNodeInfoFromID (
  626.     FWXNodeID            nodeID)
  627. {
  628.     WindowDataPtr        pWinData;
  629.     OpenNodePtr            pOpenNode;
  630.     Boolean                found;
  631.     
  632.     pWinData = (WindowDataPtr) GetWRefCon(gpFWXAppData->pSenderWindow);
  633.     pOpenNode = pWinData->pOpenNodeList;
  634.  
  635.     found = false;
  636.     while ((pOpenNode != nil) && (!found))
  637.     {
  638.         if (pOpenNode->nodeID == nodeID)
  639.             found = true;
  640.         else
  641.             pOpenNode = pOpenNode->pNextNode;
  642.     }
  643.     return pOpenNode;
  644. }
  645.  
  646. ////////////////////////////////////////////////////////////////////////////////
  647. //
  648. //    SendFWXInfo
  649. //
  650. //    Send our info to another node. Get the sharing setup machine name out
  651. //    of string resource.
  652. //
  653. OSErr SendFWXInfo(
  654.     FWXNodeID            nodeID,
  655.     UInt32                sendType)
  656. {
  657.     Handle                hString;
  658.     IOParamPtr            pIOPb;
  659.     FWXPacketPtr        pPktInfo;
  660.     SInt16                curResFile;
  661.     OSErr                err = noErr;
  662.  
  663.     // Get the sharing setup macintosh name
  664.     curResFile = CurResFile();
  665.     UseResFile(kSystemResFile);
  666.     hString = Get1Resource('STR ', kNetworkNameID);
  667.  
  668.     if ((hString != nil) && (**hString != 0))
  669.     {
  670.         FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  671.         if (pIOPb != nil)
  672.         {
  673.             SetupFWControlPB(pIOPb);
  674.             // SetupFWControlPB will leave an invalid node id in nameptr at this point
  675.             pIOPb->ioNamePtr = (StringPtr) nodeID;
  676.             
  677.             // copy the string into the data buffer
  678.             pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  679.             pPktInfo->packetType = sendType;
  680.             pIOPb->ioMisc = (Ptr) sendType;
  681.             BlockMove(*hString, (Ptr) &pPktInfo->packetData, **hString + 1);
  682.             pIOPb->ioReqCount = **hString + 1 + 4;    // length of string plus packet header
  683.             
  684.             err = CallFWXNode(pIOPb);
  685.         }
  686.         else
  687.         {
  688.             err = qErr;
  689.             FWDebugStr("\pNo buffer for SendFWXInfo");
  690.         }
  691.  
  692.         ReleaseResource(hString);
  693.     }
  694.     else
  695.     {
  696.         HandleStopAlert(kNoNameAlertID);
  697.         ExitToShell();
  698.     }
  699.     UseResFile(curResFile);
  700.     return err;
  701. }
  702.  
  703. ////////////////////////////////////////////////////////////////////////////////
  704. //
  705. //    SendFWXQuit
  706. //
  707. //    Send a quit notification to each receive node.
  708. //
  709. OSErr SendFWXQuit(void)
  710. {
  711.     WindowDataPtr        pWinData;
  712.     OpenNodePtr            pOpenNode;
  713.     IOParamPtr            pIOPb;
  714.     FWXPacketPtr        pPktInfo;
  715.     SInt16                i;
  716.     OSErr                err = noErr;
  717.  
  718.     pWinData = (WindowDataPtr) GetWRefCon(gpFWXAppData->pSenderWindow);
  719.     if (pWinData != nil)
  720.     {        
  721.         pOpenNode = pWinData->pOpenNodeList;
  722.         for (i = 0; i < pWinData->numOpenNodes; i++)
  723.         {
  724.             FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  725.             if (pIOPb != nil)
  726.             {
  727.                 SetupFWControlPB(pIOPb);
  728.                 // SetupFWWritePB will leave an invalid driver id in nameptr at this point
  729.                 pIOPb->ioNamePtr = (StringPtr) pOpenNode->nodeID;
  730.                 
  731.                 // copy the string into the data buffer
  732.                 pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  733.                 pPktInfo->packetType = kQuitNotify;
  734.                 pIOPb->ioMisc = (Ptr) kQuitNotify;
  735.                 pIOPb->ioReqCount = 4;
  736.                 
  737.                 err = CallFWXNode(pIOPb);
  738.             }
  739.             else
  740.             {
  741.                 err = qErr;
  742.                 FWDebugStr("\pNo buffer for SendFWXQuit");
  743.             }
  744.             pOpenNode = (OpenNodePtr) pOpenNode->pNextNode;
  745.         }
  746.     }
  747.     else
  748.         err = resNotFound;
  749.  
  750.     return err;
  751. }
  752.  
  753. ////////////////////////////////////////////////////////////////////////////////
  754. //
  755. //    SetupFWXRead
  756. //
  757. //    Create control buffers and a data buffer and pass the buffers to
  758. //    the driver.
  759. //
  760. static OSErr SetupFWXRead(
  761.     FWXNodeID            nodeID)
  762. {
  763.     IOParamPtr            pIOPb;
  764.     SInt16                i;
  765.     OSErr                err = noErr;
  766.  
  767.     // create control receive parameter block, receive buffer, and issue read
  768.     for (i=0; i < kFWReadControlBufs; i++) {
  769.         pIOPb = (IOParamPtr) NewPtrClear(sizeof(IOParam));
  770.         if (pIOPb != nil) {
  771.             HoldMemory ((Ptr) pIOPb, sizeof(IOParam));
  772.         } else {
  773.             FWDebugStr("\pOut of memory, SetupReadQueue");
  774.             err = memFullErr;
  775.             break;
  776.         }
  777.         
  778.         pIOPb->ioBuffer = NewPtr(kFWReadControlBufSize);
  779.         if (pIOPb->ioBuffer != nil) {
  780.             HoldMemory (pIOPb->ioBuffer, kFWReadControlBufSize);
  781.         } else {
  782.             UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  783.             DisposePtr((Ptr) pIOPb);
  784.             FWDebugStr("\pOut of memory, SetupReadQueue");
  785.             err = memFullErr;
  786.             break;
  787.         }
  788.         
  789.         // set up parameter block
  790.         pIOPb->ioNamePtr = (StringPtr) nodeID;
  791.         pIOPb->ioTrap = kFWXRead;
  792.         pIOPb->ioCompletion = (IOCompletionUPP) HandleFWReadComplete;
  793.         pIOPb->ioReqCount = kFWReadControlBufSize;
  794.  
  795.         err = CallFWXNode(pIOPb);
  796.         if (err != noErr) {
  797.             sprintf(debugStr, "Error in CallFWXNode, SetupReadQueue: %d", err);
  798.             FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  799.             break;
  800.         }
  801.     }
  802.     
  803.     if (err == noErr) {
  804.         // setup the data read parameter blocks
  805.         for (i=0; i < kFWReadDataBufs; i++) {
  806.             pIOPb = (IOParamPtr) NewPtrClear(sizeof(IOParam));
  807.             if (pIOPb != nil) {
  808.                 HoldMemory ((Ptr) pIOPb, sizeof(IOParam));
  809.             } else {
  810.                 FWDebugStr("\pOut of memory, SetupReadQueue");
  811.                 err = memFullErr;
  812.                 break;
  813.             }
  814.             
  815.             pIOPb->ioBuffer = NewPtr(kFWReadDataBufSize);
  816.             if (pIOPb->ioBuffer != nil) {
  817.                 HoldMemory (pIOPb->ioBuffer, kFWReadDataBufSize);
  818.             } else {
  819.                 UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  820.                 DisposePtr((Ptr) pIOPb);
  821.                 FWDebugStr("\pOut of memory, SetupReadQueue");
  822.                 err = memFullErr;
  823.                 break;
  824.             }
  825.             
  826.             // set up parameter block
  827.             pIOPb->ioNamePtr = (StringPtr) nodeID;
  828.             pIOPb->ioTrap = kFWXRead;
  829.             pIOPb->ioCompletion = (IOCompletionUPP) HandleFWReadComplete;
  830.             pIOPb->ioReqCount = kFWReadDataBufSize;
  831.             pIOPb->ioMisc = (Ptr) kForkData;
  832.         
  833.             err = CallFWXNode(pIOPb);
  834.             if (err != noErr) {
  835.                 sprintf(debugStr, "Error in CallFWXNode, SetupReadQueue: %d", err);
  836.                 FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  837.                 break;
  838.             }
  839.         }
  840.     }
  841.     return err;
  842. }
  843.  
  844. ////////////////////////////////////////////////////////////////////////////////
  845. //
  846. //    GetNodeIDFromEvent
  847. //
  848. //    Get the firewire file exchange node ID
  849. //    out of the device added or removed apple event
  850. //
  851. static OSErr GetNodeIDFromEvent(
  852.     AppleEvent            *pAEvent,
  853.     FWXNodeID            *nodeID)
  854. {
  855.     OSErr                err;
  856.     DescType            returnType;
  857.     Size                returnSize;
  858.  
  859.     err = AEGetParamPtr(pAEvent, kAEFWXNodeIDKey, kAEFWXNodeIDType, &returnType, 
  860.                         (Ptr) nodeID, sizeof(FWXNodeID), &returnSize);
  861.     return err;
  862. }
  863.  
  864. ////////////////////////////////////////////////////////////////////////////////
  865. //
  866. //    NewSenderWindow
  867. //
  868. //    Creates firwire sender window. Called when the first
  869. //    FireWire Exchange receive node is connected to the bus.
  870. //
  871.  
  872. static OSErr NewSenderWindow (void)
  873. {
  874.     WindowRef            pWin;
  875.     GrafPtr                curPort;
  876.     WindowDataPtr        pWinData;
  877.     MenuHandle            hMenu;
  878.     Rect                winRect;
  879.     OSErr                err = noErr;
  880.     
  881.     // open the window
  882.     pWin = GetNewCWindow(kWindowResourceID, nil, (WindowRef) -1);
  883.     
  884.     if (pWin == nil)
  885.         err = ResError();
  886.     else
  887.     {
  888.         // position and size window
  889.         err = GetWindowPos(&winRect);
  890.         if (err == noErr)
  891.         {
  892.             MoveWindow(pWin, winRect.left, winRect.top, false);
  893.             SizeWindow(pWin, winRect.right - winRect.left, winRect.bottom - winRect.top, false);
  894.         }
  895.         else
  896.             err = noErr;    // don't care if resource problem
  897.         
  898.         // Allocate window data structure
  899.         pWinData = (WindowDataPtr) NewPtrClear(sizeof(WindowData));
  900.         if (pWinData != nil)
  901.         {        
  902.             pWinData->numOpenNodes = 0;
  903.             pWinData->pOpenNodeList = nil;
  904.             pWinData->numRecvNodes = 0;
  905.             pWinData->pRecvNodeList = nil;
  906.             pWinData->hVScrollBar = GetNewControl(kVScrollBar, pWin);
  907.             if (pWinData->hVScrollBar == nil)
  908.                 err = ResError();
  909.             pWinData->hHScrollBar = GetNewControl(kHScrollBar, pWin);
  910.             if (pWinData->hHScrollBar == nil)
  911.                 err = ResError();
  912.             
  913.             SetWRefCon(pWin, (SInt32) pWinData);
  914.             if (err == noErr)
  915.                 AdjustScrollBars(pWin, true);
  916.         }
  917.         else
  918.         {
  919.             err = memFullErr;
  920.             DisposeWindow(pWin);
  921.         }
  922.     }
  923.     gpFWXAppData->pSenderWindow = pWin;
  924.     if (err == noErr)
  925.     {
  926.         GetPort(&curPort);
  927.         SetPort(pWin);
  928.         TextSize(9);
  929.         ClipRect(&qd.screenBits.bounds);
  930.         SetPort(curPort);
  931.     }
  932.     if (err == noErr)
  933.     {
  934.         if (gpFWXAppData->fwixPrefs & kIconView)
  935.         {
  936.             pWinData->windowView = kSmallIconView;
  937.             hMenu = GetMenuHandle(kViewMenuID);
  938.             SetItemMark(hMenu, kSmallIconMenuItem, checkMark);
  939.             SetItemMark(hMenu, kIconMenuItem, noMark);
  940.         }
  941.         else
  942.             pWinData->windowView = kLargeIconView;
  943.     }
  944.  
  945.     return err;
  946. }
  947.  
  948. //////////////////////////////////////////////////////////////////////////////
  949. //
  950. //    GetDisplayRect
  951. //
  952. //    Calculate the rectangle needed to display all of the sender window items.
  953. //
  954. static void GetDisplayRect (
  955.     Rect                    *r,
  956.     WindowPtr                pWin,
  957.     WindowDataPtr            pWinData)
  958. {
  959.     GrafPtr                    curPort;
  960.     Rect                    iconRect, textRect;
  961.     SInt16                    row, column;
  962.     SInt16                    index, count;
  963.  
  964.     GetPort(&curPort);
  965.     SetPort(pWin);
  966.     TextSize(9);
  967.  
  968.     if (pWinData->windowView == kLargeIconView)
  969.     {
  970.         row = pWinData->numRecvNodes % kLargeRowCount;
  971.         column = pWinData->numRecvNodes / kLargeRowCount;
  972.         if (column == 0)
  973.             count = row;
  974.         else
  975.             count = kLargeRowCount;
  976.             
  977.         // get smallest left value
  978.         for (index = 1; index <= count; index++)
  979.         {
  980.             GetNodeDragRect(pWin, index, &iconRect, &textRect);
  981.             if (textRect.left < iconRect.left)
  982.             {
  983.                 if (textRect.left < r->left)
  984.                     r->left = textRect.left;
  985.             }
  986.             else
  987.             {
  988.                 if (iconRect.left < r->left)
  989.                     r->left = iconRect.left;
  990.             }
  991.         }
  992.  
  993.         // get smallest top value
  994.         GetNodeDragRect(pWin, 1, &iconRect, &textRect);
  995.         if (iconRect.top < r->top)
  996.             r->top = iconRect.top;
  997.  
  998.         // get largest bottom value from lowest icon in row
  999.         GetNodeDragRect(pWin, count, &iconRect, &textRect);
  1000.         if (textRect.bottom > r->bottom)
  1001.             r->bottom = textRect.bottom;
  1002.             
  1003.         // get largest right value by checking space needed for far right column
  1004.         for (index = ((column * kLargeRowCount) + 1); index <= pWinData->numRecvNodes; index++)
  1005.         {
  1006.             GetNodeDragRect(pWin, index, &iconRect, &textRect);
  1007.             if (textRect.right > iconRect.right)
  1008.             {
  1009.                 if (textRect.right > r->right)
  1010.                     r->right = textRect.right;
  1011.             }
  1012.             else
  1013.             {
  1014.                 if (iconRect.right > r->right)
  1015.                     r->right = iconRect.right;
  1016.             }
  1017.         }                
  1018.     }
  1019.     else
  1020.     {
  1021.         row = pWinData->numRecvNodes % kSmallRowCount;
  1022.         column = pWinData->numRecvNodes / kSmallRowCount;
  1023.         if (column == 0)
  1024.             count = row;
  1025.         else
  1026.             count = kSmallRowCount;
  1027.  
  1028.         // get smallest top left value
  1029.         GetNodeDragRect(pWin, 1, &iconRect, &textRect);
  1030.         if (iconRect.top < r->top)
  1031.             r->top = iconRect.top;
  1032.         if (iconRect.left < r->left)
  1033.             r->left = iconRect.left;
  1034.  
  1035.         // get largest bottom value from lowest icon in row
  1036.         GetNodeDragRect(pWin, count, &iconRect, &textRect);
  1037.         if (iconRect.bottom > r->bottom)
  1038.             r->bottom = iconRect.bottom;
  1039.             
  1040.         // get largest right value by checking space needed for far right column
  1041.         for (index = ((column * kSmallRowCount) + 1); index <= pWinData->numRecvNodes; index++)
  1042.         {
  1043.             GetNodeDragRect(pWin, index, &iconRect, &textRect);
  1044.             if (textRect.right > r->right)
  1045.                 r->right = textRect.right;
  1046.         }                
  1047.     }    
  1048.     SetPort(curPort);
  1049. }
  1050.  
  1051. //////////////////////////////////////////////////////////////////////////////
  1052. //
  1053. //    AdjustScrollBars
  1054. //
  1055. //    Adjust and size scroll bars
  1056. //
  1057. OSErr AdjustScrollBars (
  1058.     WindowPtr                pWin,
  1059.     Boolean                    adjustSizes)
  1060. {
  1061.     WindowDataPtr            pWinData;
  1062.     Rect                    viewRect,        // view able area in window
  1063.                             displayRect;    // area needed to display node list
  1064.     Rect                    ctlRect;
  1065.     SInt16                    displayH, displayV, viewH, viewV;
  1066.     SInt16                    ctlVal;
  1067.     OSErr                    err = noErr;
  1068.  
  1069.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  1070.     if (pWinData != nil)
  1071.     {
  1072.         // calculate view space available
  1073.         viewRect = pWin->portRect;
  1074.         viewRect.bottom -= kScrollBarAdjust;
  1075.         viewRect.right -= kScrollBarAdjust;
  1076.         displayRect = viewRect;
  1077.         
  1078.         GetDisplayRect (&displayRect, pWin, pWinData);
  1079.         displayH = displayRect.right - displayRect.left;
  1080.         viewH = viewRect.right - viewRect.left;
  1081.         
  1082.         if (displayH > viewH)
  1083.         {
  1084.             SetControlMaximum (pWinData->hHScrollBar, displayH - viewH);
  1085.             ctlVal = GetControlValue(pWinData->hHScrollBar);
  1086.             SetControlValue (pWinData->hHScrollBar, ctlVal + (viewRect.left - displayRect.left));
  1087.         }
  1088.         else
  1089.         {
  1090.             SetControlMaximum (pWinData->hHScrollBar, 0);
  1091.             SetControlValue (pWinData->hHScrollBar, 0);
  1092.         }
  1093.     
  1094.         displayV = displayRect.bottom - displayRect.top;
  1095.         viewV = viewRect.bottom - viewRect.top;
  1096.         if (displayV > viewV)
  1097.         {
  1098.             SetControlMaximum (pWinData->hVScrollBar, displayV - viewV);
  1099.             ctlVal = GetControlValue(pWinData->hVScrollBar);
  1100.             SetControlValue (pWinData->hVScrollBar, ctlVal + (viewRect.top - displayRect.top));
  1101.         }
  1102.         else
  1103.         {
  1104.             SetControlMaximum (pWinData->hVScrollBar, 0);
  1105.             SetControlValue (pWinData->hVScrollBar, 0);
  1106.         }
  1107.         
  1108.         if (adjustSizes)
  1109.         {
  1110.             // position and size vertical scroll bar
  1111.             ctlRect = pWin->portRect;
  1112.             MoveControl (pWinData->hVScrollBar,
  1113.                          ctlRect.right - kScrollBarAdjust,
  1114.                          -1);
  1115.             SizeControl (pWinData->hVScrollBar,
  1116.                          kScrollBarWidth,
  1117.                          (ctlRect .bottom - ctlRect.top) - (kScrollBarAdjust - kScrollBarTweek));
  1118.     
  1119.             // position and size horizontal scroll bar
  1120.             MoveControl (pWinData->hHScrollBar,
  1121.                          -1,
  1122.                          ctlRect.bottom - kScrollBarAdjust);
  1123.             SizeControl (pWinData->hHScrollBar,
  1124.                          (ctlRect.right - ctlRect.left) - (kScrollBarAdjust - kScrollBarTweek),
  1125.                          kScrollBarWidth);
  1126.         }
  1127.     }
  1128.     else
  1129.         err = resNotFound;
  1130.     return  err;
  1131. }
  1132.  
  1133. //////////////////////////////////////////////////////////////////////////////
  1134. //
  1135. //    InitRecvNode
  1136. //
  1137. //    Set up the node drag rectangles and node list.
  1138. //
  1139. OSErr InitRecvNode (
  1140.     FWXNodeID                nodeID,
  1141.     ConstStr255Param        nodeName)
  1142. {
  1143.     WindowPtr                pWin;
  1144.     WindowDataPtr            pWinData;
  1145.     RecvNodePtr                pRecvNode;
  1146.     RecvNodePtr                pTempRecvNode;
  1147.     SInt16                    rctTop, rctLeft, rctBottom, rctRight;
  1148.     SInt16                    row, column;    
  1149.     SInt16                    sLoc, sWidth;    
  1150.     OSErr                    err = noErr;
  1151.     
  1152.     pWin = gpFWXAppData->pSenderWindow;
  1153.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  1154.     if (pWinData == nil)
  1155.         return memFullErr;
  1156.         
  1157.     pRecvNode = (RecvNodePtr) NewPtrClear(sizeof(RecvNodeRecord));
  1158.     if (pRecvNode == nil)
  1159.         return memFullErr;
  1160.  
  1161.     pRecvNode->pReplyTimer = (MyTMTaskPtr) NewPtrClear(sizeof(MyTMTask));
  1162.     if (pRecvNode->pReplyTimer == nil)
  1163.         return memFullErr;
  1164.     else
  1165.     {
  1166.         pRecvNode->pReplyTimer->timerTask.tmAddr = NewTimerProc(HandleReplyTimeout);
  1167.         if (pRecvNode->pReplyTimer->timerTask.tmAddr == nil)
  1168.             return memFullErr;
  1169.             
  1170.         InsTime((QElemPtr) pRecvNode->pReplyTimer);
  1171.     }
  1172.  
  1173.     // init values
  1174.     pRecvNode->nodeID = nodeID;
  1175.     BlockMove(nodeName, pRecvNode->nodeName, nodeName[0] + 1);
  1176.     sWidth = StringWidth(pRecvNode->nodeName);
  1177.  
  1178.     // setup node drag rectangle
  1179.     if (pWinData->windowView == kLargeIconView)
  1180.     {
  1181.         row = pWinData->numRecvNodes % kLargeRowCount;
  1182.         column = pWinData->numRecvNodes / kLargeRowCount;
  1183.         rctLeft = kLargeHFill + (column * kLargeHSize);
  1184.         rctRight = rctLeft + kLargeIconFill;
  1185.         rctTop = kLargeVFill + (row * kLargeVSize);
  1186.         rctBottom = rctTop + kLargeIconFill;
  1187.  
  1188.         sLoc = rctLeft + ((rctRight - rctLeft) / 2);
  1189.         sLoc -= ((sWidth / 2) + 2);
  1190.         SetRect(&pRecvNode->recvNodeTextRect,
  1191.                 sLoc,
  1192.                 rctBottom,
  1193.                 sLoc + sWidth + 3,
  1194.                 rctBottom + 13); 
  1195.     }
  1196.     else
  1197.     {
  1198.         row = pWinData->numRecvNodes % kSmallRowCount;
  1199.         column = pWinData->numRecvNodes / kSmallRowCount;
  1200.         rctLeft = kSmallHFill + (column * kSmallHSize);
  1201.         rctRight = rctLeft + kSmallIconFill;
  1202.         rctTop = kSmallVFill + (row * kSmallVSize);
  1203.         rctBottom = rctTop + kSmallIconFill;
  1204.  
  1205.         SetRect(&pRecvNode->recvNodeTextRect,
  1206.                 rctRight + 2,
  1207.                 rctBottom - 15,
  1208.                 rctRight + sWidth + 5,
  1209.                 rctBottom - 2); 
  1210.     }    
  1211.     SetRect(&pRecvNode->recvNodeIconRect, rctLeft, rctTop, rctRight, rctBottom); 
  1212.     
  1213.     // increment node count after updating rectangles
  1214.     pWinData->numRecvNodes++;
  1215.     
  1216.     // add the node to the list, if the the first node, just point to it
  1217.     if (pWinData->numRecvNodes == 1)
  1218.         pWinData->pRecvNodeList = pRecvNode;
  1219.     else
  1220.     {
  1221.     // it is not the first node, traverse the list, add new node to the end
  1222.         pTempRecvNode = pWinData->pRecvNodeList;
  1223.         while (pTempRecvNode->pNextNode != nil)
  1224.             pTempRecvNode = pTempRecvNode->pNextNode;
  1225.         pTempRecvNode->pNextNode = pRecvNode;
  1226.         pRecvNode->pPreviousNode = pTempRecvNode;
  1227.     }
  1228.  
  1229.     AdjustScrollBars(pWin, false);
  1230.  
  1231.     return err;
  1232. }
  1233.  
  1234. //////////////////////////////////////////////////////////////////////////////
  1235. //
  1236. //    HandleReplyTimeout
  1237. //
  1238. //    For various communications with nodes, fwix posts a timer to wait for
  1239. //    a reply. If no reply is received this task is executed.
  1240. // 
  1241. //    JKL *** needs to have a variable timer to increase timeout period from
  1242. //    a few seconds up to a couple of minutes and eventually give up
  1243. // 
  1244. static pascal void HandleReplyTimeout (
  1245.     MyTMTaskPtr            pTMTask)
  1246. {
  1247.     gSendError = pTMTask->nodeID;
  1248. }
  1249.  
  1250. //////////////////////////////////////////////////////////////////////////////
  1251. //
  1252. //    HandleDeviceRemovedEvent
  1253. //
  1254. //    Called when a FWIX receiver node disconnects from the bus. If the node
  1255. //    had fwix open, clean up the node info and any sends. Otherwise close the node.
  1256. // 
  1257. //    JKL *** what if we are receiving data from this node? handle by HandleReceive timeout?
  1258. static pascal OSErr    HandleDeviceRemovedEvent (
  1259.     AppleEvent                *theAppleEvent,
  1260.     AppleEvent                *reply,
  1261.     long                    handlerRefcon)
  1262. {
  1263.     WindowDataPtr            pWinData;
  1264.     GrafPtr                    curPort;
  1265.     GrafPtr                    pWindowPort;
  1266.     RecvNodePtr                pTempRecvNode;
  1267.     OpenNodePtr                pTempOpenNode;
  1268.     FWXNodeID                targetNodeID;
  1269.     TxFSSpecPtr                pTxItem;
  1270.     OSErr                    err;
  1271.     Boolean                    foundNodeID;
  1272.  
  1273.     err = GetNodeIDFromEvent(theAppleEvent, &targetNodeID);
  1274.     if ((err == noErr) && (gSendingFile || gCheckingTransfer))
  1275.     {
  1276.         // if we are sending a file to the removed node,
  1277.         // dismiss the dialog, clean up send queue, and alert user
  1278.         if (targetNodeID == ((TxFSSpecPtr) gSendQHdr.qHead)->recvNode)
  1279.         {
  1280.             gCheckingTransfer = false;
  1281.             gSendingFile = false;
  1282.             gForkComplete = true;
  1283.             gForkWriteComplete = true;
  1284.             CleanupCopyDialog(FrontWindow());
  1285.             if (gSendingDataFork || gSendingResFork)
  1286.             {
  1287.                 gSendingDataFork = false;
  1288.                 gSendingResFork = false;
  1289.                 FSClose(gCurForkRefNum);
  1290.             }
  1291.     
  1292.             // dequeue and dispose of all file queue entries
  1293.             pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  1294.             while (pTxItem != nil)
  1295.             {
  1296.                 Dequeue((QElemPtr) pTxItem, &gSendQHdr);
  1297.                 DisposePtr((Ptr) pTxItem->pFSSpec);
  1298.                 DisposePtr((Ptr) pTxItem);
  1299.  
  1300.                 // get another queue item
  1301.                 pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  1302.             }
  1303.             
  1304.             GetNodeInfo(targetNodeID, &pTempRecvNode);
  1305.             ParamText(pTempRecvNode->nodeName, "\p", "\p", "\p");
  1306.             HandleCautionAlert(kNodeDisconnectAlertID);
  1307.         }
  1308.     }
  1309.     
  1310.     // Get the window data record
  1311.     pWinData = (WindowDataPtr) GetWRefCon(gpFWXAppData->pSenderWindow);
  1312.     
  1313.     // Traverse the open node list to find the node record for the nodeID
  1314.     foundNodeID = false;
  1315.     pTempOpenNode = pWinData->pOpenNodeList;
  1316.     while ((pTempOpenNode != nil) && (!foundNodeID))
  1317.     {
  1318.         if (pTempOpenNode->nodeID == targetNodeID)
  1319.         {
  1320.             foundNodeID = true;
  1321.             break;
  1322.         }
  1323.         pTempOpenNode = pTempOpenNode->pNextNode;    
  1324.     }
  1325.  
  1326.     if (foundNodeID)
  1327.     {    
  1328.         // handle removing the node from the open node list
  1329.         if (pTempOpenNode->pNextNode != nil)
  1330.             pTempOpenNode->pNextNode->pPreviousNode = pTempOpenNode->pPreviousNode;
  1331.  
  1332.         if (pTempOpenNode->pPreviousNode != nil)
  1333.             pTempOpenNode->pPreviousNode->pNextNode = pTempOpenNode->pNextNode;
  1334.         else
  1335.             pWinData->pOpenNodeList = pTempOpenNode->pNextNode;
  1336.             
  1337.         DisposePtr((Ptr) pTempOpenNode);
  1338.         pWinData->numOpenNodes--;
  1339.         CloseFWXNode(targetNodeID);
  1340.     }
  1341.     
  1342.     // Traverse the receive node list to find the receive node record for the nodeID
  1343.     foundNodeID = false;
  1344.     pTempRecvNode = pWinData->pRecvNodeList;
  1345.     while ((pTempRecvNode != nil) && (!foundNodeID))
  1346.     {
  1347.         if (pTempRecvNode->nodeID == targetNodeID)
  1348.         {
  1349.             foundNodeID = true;
  1350.             break;
  1351.         }
  1352.         pTempRecvNode = pTempRecvNode->pNextNode;
  1353.     }
  1354.         
  1355.     if (foundNodeID)
  1356.     {    
  1357.         // remove the node from the list
  1358.         if (pTempRecvNode->pNextNode != nil)
  1359.             pTempRecvNode->pNextNode->pPreviousNode = pTempRecvNode->pPreviousNode;
  1360.             
  1361.         if (pTempRecvNode->pPreviousNode != nil)
  1362.             pTempRecvNode->pPreviousNode->pNextNode = pTempRecvNode->pNextNode;
  1363.         else
  1364.             pWinData->pRecvNodeList = pTempRecvNode->pNextNode;
  1365.         
  1366.         // JKL *** how about canceling timer?
  1367.         if (pTempRecvNode->pReplyTimer != nil)
  1368.         {
  1369.             if (pTempRecvNode->pReplyTimer->timerTask.tmAddr != nil)
  1370.                 DisposeRoutineDescriptor(pTempRecvNode->pReplyTimer->timerTask.tmAddr);
  1371.             DisposePtr((Ptr) pTempRecvNode->pReplyTimer);
  1372.         }
  1373.         DisposePtr((Ptr) pTempRecvNode);
  1374.         pWinData->numRecvNodes--;
  1375.         
  1376.         if (pWinData->numRecvNodes == 0)
  1377.         {
  1378.             HideWindow(gpFWXAppData->pSenderWindow);
  1379.             DisableItem(GetMenuHandle(kFileMenuID), kOpenMenuItem);
  1380.             DisableItem(GetMenuHandle(kFileMenuID), kCloseMenuItem);
  1381.             DisableItem(GetMenuHandle(kViewMenuID), 0);
  1382.             DrawMenuBar();
  1383.         }
  1384.         else
  1385.         {
  1386.             // Force an update
  1387.             GetPort(&curPort);
  1388.             pWindowPort = (GrafPtr) GetWindowPort(gpFWXAppData->pSenderWindow);
  1389.             AdjustNodeIcons(pWinData, &pWindowPort->portRect);
  1390.             AdjustScrollBars(gpFWXAppData->pSenderWindow, false);
  1391.             SetPortWindowPort(pWindowPort);
  1392.             InvalRect(&pWindowPort->portRect);
  1393.             SetPort(curPort);
  1394.         }
  1395.     }
  1396.     return err;
  1397. }
  1398.  
  1399. //////////////////////////////////////////////////////////////////////////////
  1400. //
  1401. //    AdjustNodeIcons
  1402. //
  1403. //    Adjust the placement of the node icons in the window. Traverse the list
  1404. //    of nodes setting the rectangle appropriately.
  1405. //
  1406.  
  1407. void AdjustNodeIcons (
  1408.     WindowDataPtr            pWinData,
  1409.     Rect                    *windRect)
  1410. {
  1411.     RecvNodePtr                pRecvNode;
  1412.     SInt16                    rctTop, rctLeft, rctBottom, rctRight;
  1413.     SInt16                    row, column;
  1414.     SInt16                    index;
  1415.     SInt16                    sWidth, sLoc;
  1416.     
  1417.     pRecvNode = pWinData->pRecvNodeList;
  1418.     for (index = 0; index < pWinData->numRecvNodes; index++)
  1419.     {
  1420.         if (pRecvNode == nil)
  1421.             FWDebugStr("\pNode List screwed up in AdjustNodeIcons");
  1422.             
  1423.         // setup drag rectangle
  1424.         sWidth = StringWidth(pRecvNode->nodeName);
  1425.         if (pWinData->windowView == kLargeIconView)
  1426.         {
  1427.             row = index % kLargeRowCount;
  1428.             column = index / kLargeRowCount;
  1429.             rctLeft = kLargeHFill + (column * kLargeHSize);
  1430.             rctRight = rctLeft + kLargeIconFill;
  1431.             rctTop = kLargeVFill + (row * kLargeVSize);
  1432.             rctBottom = rctTop + kLargeIconFill;
  1433.  
  1434.             sLoc = rctLeft + ((rctRight - rctLeft) / 2);
  1435.             sLoc -= ((sWidth / 2) + 2);
  1436.             SetRect(&pRecvNode->recvNodeTextRect,
  1437.                     sLoc,
  1438.                     rctBottom,
  1439.                     sLoc + sWidth + 3,
  1440.                     rctBottom + 13); 
  1441.         }
  1442.         else
  1443.         {
  1444.             row = index % kSmallRowCount;
  1445.             column = index / kSmallRowCount;
  1446.             rctLeft = kSmallHFill + (column * kSmallHSize);
  1447.             rctRight = rctLeft + kSmallIconFill;
  1448.             rctTop = kSmallVFill + (row * kSmallVSize);
  1449.             rctBottom = rctTop + kSmallIconFill;
  1450.  
  1451.             SetRect(&pRecvNode->recvNodeTextRect,
  1452.                     rctRight + 2,
  1453.                     rctBottom - 15,
  1454.                     rctRight + sWidth + 5,
  1455.                     rctBottom - 2); 
  1456.         }    
  1457.         SetRect(&pRecvNode->recvNodeIconRect, rctLeft, rctTop, rctRight, rctBottom);
  1458.         pRecvNode = (RecvNodePtr) pRecvNode->pNextNode;
  1459.     }
  1460. }
  1461.  
  1462.  
  1463. //////////////////////////////////////////////////////////////////////////////
  1464. //
  1465. //    HandleGetNodeListEvent
  1466. //
  1467. //    Handle the get node list applescript command
  1468. //
  1469.  
  1470. static pascal OSErr HandleGetNodeListEvent (
  1471.     AppleEvent                *pAppleEvent,
  1472.     AppleEvent                *pReplyEvent,
  1473.     SInt32                    refCon)
  1474. {
  1475.     WindowDataPtr    pWinData;
  1476.     RecvNodePtr        pNodeInfo;
  1477.     AEDescList        nodeList;
  1478.        OSErr            err = noErr;
  1479.  
  1480.     err = AECreateList(nil, 0, false, &nodeList);
  1481.     if (err == noErr) {
  1482.     
  1483.         pWinData = (WindowDataPtr) GetWRefCon(gpFWXAppData->pSenderWindow);
  1484.         if (pWinData != nil)
  1485.         {
  1486.             pNodeInfo = pWinData->pRecvNodeList;
  1487.             while ((pNodeInfo != nil) && (!err))
  1488.             {
  1489.                 err = AEPutPtr(&nodeList, 0, typeChar, pNodeInfo->nodeName + 1, pNodeInfo->nodeName[0]);
  1490.                 pNodeInfo = pNodeInfo->pNextNode;
  1491.             }
  1492.             if (err == noErr)
  1493.                 err = AEPutKeyDesc(pReplyEvent, keyDirectObject, &nodeList);
  1494.         }
  1495.     }
  1496.     
  1497.     return  err;
  1498. }
  1499.  
  1500. //////////////////////////////////////////////////////////////////////////////
  1501. //
  1502. //    HandleSendItemsEvent
  1503. //
  1504. //    Handle the send applescript command
  1505. //
  1506. static pascal OSErr HandleSendItemsEvent (
  1507.     AppleEvent                *pAppleEvent,
  1508.     AppleEvent                *pReplyEvent,
  1509.     SInt32                    refCon)
  1510. {
  1511.     FWXNodeID                *pNodeIDList = nil;
  1512.     FSSpecPtr                pFileSpecList = nil;
  1513.     AESendRecPtr            pAESendElem;
  1514.     UInt16                    numFSItems;
  1515.     UInt16                    numNodes;
  1516.     UInt16                    index;
  1517.     OSErr                    err;
  1518.     
  1519.     // get items to be sent from event
  1520.     err = GetFSItemsFromEvent(&pFileSpecList, pAppleEvent, &numFSItems);
  1521.  
  1522.     // get the list of receive targets from event
  1523.     if (err == noErr)
  1524.         err = GetReceiveNodesFromEvent(&pNodeIDList, pAppleEvent, &numNodes);
  1525.         
  1526.     if (err == noErr)
  1527.     {
  1528.         for (index = 0; index < numNodes; index++)
  1529.         {
  1530.             pAESendElem = (AESendRecPtr) NewPtr(sizeof(AESendRec));
  1531.             if (pAESendElem == nil)
  1532.             {
  1533.                 err = memFullErr;
  1534.                 break;
  1535.             }
  1536.             else
  1537.             {
  1538.                 pAESendElem->pSendItemsList = (FSSpecPtr) NewPtr(sizeof(FSSpec) * numFSItems);
  1539.                 if (pAESendElem->pSendItemsList != nil)
  1540.                 {
  1541.                     BlockMove(pFileSpecList, pAESendElem->pSendItemsList, sizeof(FSSpec) * numFSItems);
  1542.                     pAESendElem->recvNode = pNodeIDList[index];
  1543.                     pAESendElem->numSendItems = numFSItems;
  1544.                     Enqueue((QElemPtr) pAESendElem, &gAESendQHdr);
  1545.                 }
  1546.                 else
  1547.                 {
  1548.                     err = memFullErr;
  1549.                     break;
  1550.                 }
  1551.             }
  1552.         }
  1553.     }
  1554.     
  1555.     if (pNodeIDList != nil)
  1556.         DisposePtr((Ptr) pNodeIDList);
  1557.     if (pFileSpecList != nil)
  1558.         DisposePtr((Ptr) pFileSpecList);
  1559.         
  1560.     if (!(gSendingFile || gCheckingTransfer))
  1561.     {
  1562.         pAESendElem = (AESendRecPtr) gAESendQHdr.qHead;
  1563.         if (pAESendElem != nil)
  1564.         {
  1565.             Dequeue((QElemPtr) pAESendElem, &gAESendQHdr);
  1566.             SendFSSpecListToSelf(pAESendElem->recvNode, pAESendElem->pSendItemsList, pAESendElem->numSendItems);
  1567.             DisposePtr((Ptr) pAESendElem->pSendItemsList);
  1568.             DisposePtr((Ptr) pAESendElem);
  1569.         }
  1570.     }
  1571.     
  1572.     err = AEPutKeyPtr(pReplyEvent, keyDirectObject, typeShortInteger, &err, sizeof(OSErr));
  1573.     return err;
  1574. }
  1575.  
  1576. //////////////////////////////////////////////////////////////////////////////
  1577. //
  1578. //    GetReceiveNodesFromEvent
  1579. //
  1580. //    Get the target nodes for the transfer out of the event
  1581. //
  1582. static OSErr GetReceiveNodesFromEvent (
  1583.     FWXNodeID                **pReceiveNodeIDList,
  1584.     AppleEvent                *pAppleEvent,
  1585.     UInt16                    *numNodes)
  1586. {    
  1587.     Ptr                        p = nil;
  1588.     AEDescList                descriptorList;
  1589.     SInt32                    itemCount;
  1590.     AEKeyword                keywd;
  1591.     DescType                returnedType;
  1592.     Size                    actualSize;
  1593.     UInt16                    i;
  1594.     OSErr                    err;
  1595.     
  1596.     err = AEGetParamDesc(pAppleEvent, kAEFWXNodeKeyword, typeAEList, &descriptorList);
  1597.     if (err == noErr)
  1598.     {
  1599.         err = AECountItems(&descriptorList, &itemCount);
  1600.         if (err == noErr)
  1601.         {
  1602.             *numNodes = itemCount;
  1603.             *pReceiveNodeIDList = (FWXNodeID *) NewPtr(sizeof(FWXNodeID) * itemCount);
  1604.             if (*pReceiveNodeIDList == nil)
  1605.                 err = memFullErr;
  1606.         }
  1607.     
  1608.         if (err == noErr)
  1609.         {
  1610.             for (i = 1; i <= itemCount; i++)
  1611.             {
  1612.                 err = AEGetNthPtr(&descriptorList, i, typeChar, &keywd, &returnedType,
  1613.                                     p, 0, &actualSize);
  1614.                 if (err == noErr)
  1615.                 {
  1616.                     p = NewPtr(actualSize + 1);
  1617.                     if (p == nil)
  1618.                     {
  1619.                         err = memFullErr;
  1620.                         break;
  1621.                     }
  1622.                     
  1623.                     err = AEGetNthPtr(&descriptorList, i, typeChar, &keywd, &returnedType,
  1624.                                     p + 1, actualSize, &actualSize);
  1625.                     p[0] = actualSize;
  1626.                     err = GetNodeIDFromName(&((*pReceiveNodeIDList)[i-1]), (ConstStr255Param) p);
  1627.                     DisposePtr(p);
  1628.                     if (err != noErr)
  1629.                         break;
  1630.                 }
  1631.             }
  1632.         }
  1633.         AEDisposeDesc(&descriptorList);
  1634.     }
  1635.     return err;
  1636. }
  1637.  
  1638. //////////////////////////////////////////////////////////////////////////////
  1639. //
  1640. //    GetNodeIDFromName
  1641. //
  1642. //    Get the node id from the node name.
  1643. //
  1644. static OSErr GetNodeIDFromName (
  1645.     FWXNodeID                *nodeID,
  1646.     ConstStr255Param        nodeName)
  1647. {
  1648.     WindowDataPtr            pWinData;
  1649.     RecvNodePtr                pRecvNode;
  1650.     OSErr                    err = noErr;
  1651.     
  1652.     pWinData = (WindowDataPtr) GetWRefCon(gpFWXAppData->pSenderWindow);
  1653.     if (pWinData == nil)
  1654.         return memFullErr;
  1655.         
  1656.     *nodeID = kInvalidFWXNodeID;
  1657.     pRecvNode = pWinData->pRecvNodeList;
  1658.     while (pRecvNode != nil)
  1659.     {
  1660.         if (EqualString(nodeName, pRecvNode->nodeName, false, false))
  1661.             break;
  1662.         pRecvNode = pRecvNode->pNextNode;
  1663.     }
  1664.  
  1665.     if (pRecvNode == nil)
  1666.         err = qErr;        // nodeName not found
  1667.     else
  1668.         *nodeID = pRecvNode->nodeID;
  1669.  
  1670.     return err;
  1671. }
  1672.  
  1673.  
  1674. //////////////////////////////////////////////////////////////////////////////
  1675. //
  1676. //    GetFSItemsFromEvent
  1677. //
  1678. //    Get the list of items to be sent out of the appleevent.
  1679. //
  1680. static OSErr GetFSItemsFromEvent (
  1681.     FSSpecPtr                *pSendItems,
  1682.     AppleEvent                *pEvent,
  1683.     UInt16                    *numItems)
  1684. {    
  1685.     Ptr                        p;
  1686.     FSSpecPtr                pFileList;
  1687.     AEDescList                descriptorList;
  1688.     AEKeyword                keywd;
  1689.     DescType                returnedType;
  1690.     Size                    actualSize;
  1691.     SInt32                    itemCount;
  1692.     SInt32                    i;
  1693.     OSErr                    err;
  1694.  
  1695.     err = AEGetParamDesc(pEvent, keyDirectObject, typeAEList, &descriptorList);
  1696.     if (err == noErr)
  1697.     {
  1698.         err = AECountItems(&descriptorList, &itemCount);
  1699.         pFileList = (FSSpecPtr) NewPtr(sizeof(FSSpec) * itemCount);
  1700.         if (pFileList == nil)
  1701.             err = memFullErr;
  1702.         
  1703.         if (err == noErr)
  1704.         {
  1705.             for (i = 1; i <= itemCount; i++)
  1706.             {
  1707.                 err = AEGetNthPtr(&descriptorList, i, typeFSS, &keywd, &returnedType,
  1708.                                     &pFileList[i-1], sizeof(FSSpec), &actualSize);
  1709.                 if (err == errAECoercionFail)
  1710.                 {
  1711.                     // try getting the data out as string and rolling our own fsspec
  1712.                     err = AEGetNthPtr(&descriptorList, i, typeChar, &keywd, &returnedType,
  1713.                                         p, 0, &actualSize);
  1714.                     if (err == noErr)
  1715.                     {
  1716.                         p = NewPtr(actualSize + 1);
  1717.                         if (p != nil)
  1718.                         {
  1719.                             err = AEGetNthPtr(&descriptorList, i, typeChar, &keywd, &returnedType,
  1720.                                                 p + 1, actualSize, &actualSize);
  1721.                             if (err == noErr)
  1722.                             {
  1723.                                 p[0] = actualSize;
  1724.                                 err = FSMakeFSSpec(0, 0, (ConstStr255Param) p, &pFileList[i-1]);
  1725.                             }
  1726.                             DisposePtr(p);
  1727.                         }
  1728.                         else
  1729.                         {
  1730.                             err = errAECoercionFail;
  1731.                             break;
  1732.                         }
  1733.                     }
  1734.                 } 
  1735.             }
  1736.         }
  1737.         AEDisposeDesc(&descriptorList);
  1738.         *numItems = itemCount;
  1739.         *pSendItems = pFileList;
  1740.     }
  1741.     return err;
  1742. }
  1743.  
  1744.  
  1745. //////////////////////////////////////////////////////////////////////////////
  1746. //
  1747. //    HandleOpenApplicationEvent
  1748. //
  1749. //    Do nothing for now
  1750. //
  1751.  
  1752. static pascal OSErr HandleOpenApplicationEvent (
  1753.     AppleEvent                *pAppleEvent,
  1754.     AppleEvent                *pReplyEvent,
  1755.     SInt32                    refCon)
  1756. {
  1757.     return noErr;
  1758. }
  1759.  
  1760. //////////////////////////////////////////////////////////////////////////////
  1761. //
  1762. //    HandleOpenDocumentsEvent
  1763. //
  1764. //    Do nothing for now, eventually send a list of items
  1765. //
  1766.  
  1767. static pascal OSErr HandleOpenDocumentsEvent (
  1768.     AppleEvent                *pAppleEvent,
  1769.     AppleEvent                *pReplyEvent,
  1770.     SInt32                    refCon)
  1771. {
  1772.     return noErr;
  1773. }
  1774.  
  1775. //////////////////////////////////////////////////////////////////////////////
  1776. //
  1777. //    HandleQuitApplicationEvent
  1778. //
  1779. //    quit the app
  1780. //
  1781.  
  1782. static pascal OSErr HandleQuitApplicationEvent (
  1783.     AppleEvent                *pAppleEvent,
  1784.     AppleEvent                *pReplyEvent,
  1785.     SInt32                    refCon)
  1786. {
  1787.  
  1788.     HandleQuit();     // set the quit flag (doesn't immediately quit)
  1789.     return noErr;
  1790. }
  1791.  
  1792.  
  1793. //////////////////////////////////////////////////////////////////////////////
  1794. //
  1795. // InstallAppleEventHandlers
  1796. //
  1797. // Setup handlers for standard open app, open documents, quit app
  1798. // Also handler for when a user drops files on a FireWire Exchange node.
  1799. //
  1800.  
  1801. static OSErr InstallAppleEventHandlers (void)
  1802. {
  1803.     OSErr err = noErr;
  1804.     
  1805.     // Create open application event handler.
  1806.     gpFWXAppData->openApplicationEventHandler =
  1807.         NewAEEventHandlerProc (HandleOpenApplicationEvent);
  1808.     if (gpFWXAppData->openApplicationEventHandler == nil)
  1809.         err = memFullErr;
  1810.  
  1811.     // Install handler.
  1812.     if (err == noErr) {
  1813.         err = AEInstallEventHandler
  1814.                 (kCoreEventClass,
  1815.                  kAEOpenApplication,
  1816.                  gpFWXAppData->openApplicationEventHandler,
  1817.                  (SInt32) gpFWXAppData,
  1818.                  false);
  1819.         if (err == noErr) {
  1820.             gpFWXAppData->openApplicationEventHandlerInstalled =
  1821.                 true;
  1822.         }
  1823.     }
  1824.  
  1825.     if (err == noErr) {
  1826.         // Create open documents event handler.
  1827.         gpFWXAppData->openDocumentsEventHandler =
  1828.             NewAEEventHandlerProc (HandleOpenDocumentsEvent);
  1829.         if (gpFWXAppData->openDocumentsEventHandler == nil)
  1830.             err = memFullErr;
  1831.     
  1832.         // Install handler.
  1833.         if (err == noErr) {
  1834.             err = AEInstallEventHandler
  1835.                     (kCoreEventClass,
  1836.                      kAEOpenDocuments,
  1837.                      gpFWXAppData->openDocumentsEventHandler,
  1838.                      (SInt32) gpFWXAppData,
  1839.                      false);
  1840.             if (err == noErr) {
  1841.                 gpFWXAppData->openDocumentsEventHandlerInstalled =
  1842.                     true;
  1843.             }
  1844.         }
  1845.     }
  1846.  
  1847.     if (err == noErr) {
  1848.         // Create quit application event handler.
  1849.         gpFWXAppData->quitApplicationEventHandler =
  1850.             NewAEEventHandlerProc (HandleQuitApplicationEvent);
  1851.         if (gpFWXAppData->quitApplicationEventHandler == nil)
  1852.             err = memFullErr;
  1853.     
  1854.         // Install handler.
  1855.         if (err == noErr) {
  1856.             err = AEInstallEventHandler
  1857.                     (kCoreEventClass,
  1858.                      kAEQuitApplication,
  1859.                      gpFWXAppData->quitApplicationEventHandler,
  1860.                      (SInt32) gpFWXAppData,
  1861.                      false);
  1862.             if (err == noErr) {
  1863.                 gpFWXAppData->quitApplicationEventHandlerInstalled =
  1864.                     true;
  1865.             }
  1866.         }
  1867.     }
  1868.  
  1869.     if (err == noErr) {
  1870.         // Create fsspec list handler.
  1871.         gpFWXAppData->fileSpecListHandler =
  1872.             NewAEEventHandlerProc (HandleAEFileSpecList);
  1873.         if (gpFWXAppData->fileSpecListHandler == nil)
  1874.             err = memFullErr;
  1875.     
  1876.         // Install handler.
  1877.         if (err == noErr) {
  1878.             err = AEInstallEventHandler
  1879.                     (kAEFWXEventClass,
  1880.                      kAEFileSpecList,
  1881.                      gpFWXAppData->fileSpecListHandler,
  1882.                      (SInt32) gpFWXAppData,
  1883.                      false);
  1884.             if (err == noErr) {
  1885.                 gpFWXAppData->fileSpecListHandlerInstalled =
  1886.                     true;
  1887.             }
  1888.         }
  1889.     }
  1890.     
  1891.     // Create device added event handler.
  1892.     if (err == noErr) {
  1893.         gpFWXAppData->deviceAddedEventHandler =
  1894.             NewAEEventHandlerProc (HandleDeviceAddedEvent);
  1895.         if (gpFWXAppData->deviceAddedEventHandler == nil)
  1896.             err = memFullErr;
  1897.     }
  1898.  
  1899.     // Install handler.
  1900.     if (err == noErr) {
  1901.         err = AEInstallEventHandler
  1902.                 (kAEFWXEventClass,
  1903.                  kAEFWXDeviceAdded,
  1904.                  gpFWXAppData->deviceAddedEventHandler,
  1905.                  (SInt32) gpFWXAppData,
  1906.                  false);
  1907.         if (err == noErr) {
  1908.             gpFWXAppData->deviceAddedEventHandlerInstalled =
  1909.                 true;
  1910.         }
  1911.     }
  1912.  
  1913.     // Create device removed event handler.
  1914.     if (err == noErr)
  1915.     {
  1916.         gpFWXAppData->deviceRemovedEventHandler =
  1917.             NewAEEventHandlerProc (HandleDeviceRemovedEvent);
  1918.         if (gpFWXAppData->deviceRemovedEventHandler == nil)
  1919.             err = memFullErr;
  1920.     }
  1921.  
  1922.     // Install handler.
  1923.     if (err == noErr)
  1924.     {
  1925.         err = AEInstallEventHandler
  1926.                 (kAEFWXEventClass,
  1927.                  kAEFWXDeviceRemoved,
  1928.                  gpFWXAppData->deviceRemovedEventHandler,
  1929.                  (SInt32) gpFWXAppData,
  1930.                  false);
  1931.         if (err == noErr)
  1932.         {
  1933.             gpFWXAppData->deviceRemovedEventHandlerInstalled =
  1934.                 true;
  1935.         }
  1936.     }
  1937.  
  1938.     // Create device send items event handler.
  1939.     if (err == noErr)
  1940.     {
  1941.         gpFWXAppData->sendItemsEventHandler =
  1942.             NewAEEventHandlerProc (HandleSendItemsEvent);
  1943.         if (gpFWXAppData->sendItemsEventHandler == nil)
  1944.             err = memFullErr;
  1945.     }
  1946.  
  1947.     // Install handler.
  1948.     if (err == noErr)
  1949.     {
  1950.         err = AEInstallEventHandler
  1951.                 (kAEFWXEventClass,
  1952.                  kAEFWXSendEventID,
  1953.                  gpFWXAppData->sendItemsEventHandler,
  1954.                  (SInt32) gpFWXAppData,
  1955.                  false);
  1956.         if (err == noErr)
  1957.         {
  1958.             gpFWXAppData->sendItemsEventHandlerInstalled =
  1959.                 true;
  1960.         }
  1961.     }
  1962.  
  1963.     // Create get node list event handler.
  1964.     if (err == noErr)
  1965.     {
  1966.         gpFWXAppData->getNodeListEventHandler =
  1967.             NewAEEventHandlerProc (HandleGetNodeListEvent);
  1968.         if (gpFWXAppData->getNodeListEventHandler == nil)
  1969.             err = memFullErr;
  1970.     }
  1971.  
  1972.     // Install handler.
  1973.     if (err == noErr)
  1974.     {
  1975.         err = AEInstallEventHandler
  1976.                 (kAEFWXEventClass,
  1977.                  kAEFWXNodeListID,
  1978.                  gpFWXAppData->getNodeListEventHandler,
  1979.                  (SInt32) gpFWXAppData,
  1980.                  false);
  1981.         if (err == noErr)
  1982.         {
  1983.             gpFWXAppData->getNodeListEventHandlerInstalled =
  1984.                 true;
  1985.         }
  1986.     }
  1987.     return err;
  1988. }
  1989.  
  1990.  
  1991. //////////////////////////////////////////////////////////////////////////////
  1992. //
  1993. // InstallCompletionRoutineProcs
  1994. //
  1995. // Setup handlers for our file read/write async completion procs
  1996. //    and FireWire read/write async completion procs
  1997. //
  1998.  
  1999. enum {
  2000.     uppIOCompletionProcWorkaroundInfo =
  2001.         kRegisterBased |
  2002.         RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) |
  2003.         REGISTER_RESULT_LOCATION(kRegisterD0) |
  2004.         REGISTER_ROUTINE_PARAMETER(1, kRegisterA0, SIZE_CODE(sizeof(ParmBlkPtr)))
  2005. };
  2006.  
  2007. #define NewIOCompletionProcWorkaround(userRoutine)        \
  2008.         (IOCompletionUPP) NewRoutineDescriptor((ProcPtr)(userRoutine),    \
  2009.                                                uppIOCompletionProcWorkaroundInfo,    \
  2010.                                                GetCurrentArchitecture())
  2011.  
  2012. static OSErr InstallCompletionRoutineProcs (void)
  2013. {
  2014.     OSErr err = noErr;
  2015.     
  2016.     gpFWXAppData->fileReadCompletionHandler =
  2017.         NewIOCompletionProcWorkaround(HandleFileReadComplete);
  2018.  
  2019.     if (gpFWXAppData->fileReadCompletionHandler == nil)
  2020.         err = memFullErr;
  2021.     else
  2022.         HoldMemory(gpFWXAppData->fileReadCompletionHandler, 32*1024);    // JKL some large amount
  2023.  
  2024.     if (err == noErr) {
  2025.         gpFWXAppData->fileWriteCompletionHandler =
  2026.             NewIOCompletionProcWorkaround(HandleFileWriteComplete);
  2027.     
  2028.         if (gpFWXAppData->fileWriteCompletionHandler == nil)
  2029.             err = memFullErr;
  2030.         else
  2031.             HoldMemory(gpFWXAppData->fileWriteCompletionHandler, 32*1024);    // JKL some large amount
  2032.     
  2033.         // while here go ahead and hold some other interrupt level stuff
  2034.         HoldMemory(HandleFWWriteComplete, 32*1024);
  2035.         HoldMemory(HandleFWReadComplete, 32*1024);
  2036.         HoldMemory(HandleFWControlComplete, 32*1024);
  2037.         HoldMemory(FWIXDequeue, 32*1024);
  2038.         HoldMemory(SetupFileReadPB, 32*1024);
  2039.         HoldMemory(&gFileReadQHdr, 32*1024);
  2040.         HoldMemory(&gFWControlQHdr, 32*1024);
  2041.         HoldMemory(&gReceiveQHdr, 32*1024);
  2042.     }
  2043.  
  2044.     return err;
  2045.  
  2046. }
  2047.  
  2048. ////////////////////////////////////////////////////////////////////////////////
  2049. //
  2050. // DrawWindow
  2051. //
  2052. //    Draws the space areas in the window
  2053. //
  2054. static void DrawWindow (
  2055.     WindowPtr            pWin)
  2056. {
  2057.     Handle                hIconSuite;
  2058.     RgnHandle            hOldClip;
  2059.     WindowDataPtr        pWinData;
  2060.     StringPtr            pString;
  2061.     Rect                iconRect, textRect;
  2062.     Rect                drawRect;
  2063.     SInt16                nodeIndex;
  2064.     OSErr                err;
  2065.     
  2066.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2067.     if (pWinData != nil)
  2068.     {
  2069.         GetClip(hOldClip = NewRgn());
  2070.         EraseRect(&pWin->portRect);
  2071.         DrawControls(pWin);
  2072.         DrawGrowIcon(pWin);
  2073.     
  2074.         SetOrigin (GetControlValue(pWinData->hHScrollBar),
  2075.                    GetControlValue(pWinData->hVScrollBar));
  2076.         drawRect = pWin->portRect;
  2077.         drawRect.bottom -= kScrollBarAdjust;
  2078.         drawRect.right -= kScrollBarAdjust;
  2079.         ClipRect(&drawRect);
  2080.         
  2081.         err = GetIconSuite(&hIconSuite, kDropIconSuiteID, svAllAvailableData);
  2082.         for (nodeIndex = 1; nodeIndex <= pWinData->numRecvNodes; nodeIndex ++)
  2083.         {
  2084.             GetNodeDragRect(pWin, nodeIndex, &iconRect, &textRect);
  2085.             GetNodeName(pWin, nodeIndex, &pString);
  2086.             PlotIconSuite(&iconRect, atNone, ttNone, hIconSuite);
  2087.             InsetRect(&textRect, 1, 0);
  2088.             TETextBox(pString + 1, pString[0], &textRect, teJustLeft);
  2089.         }
  2090.         DisposeIconSuite(hIconSuite, false);
  2091.         SetOrigin(0, 0);
  2092.         SetClip(hOldClip);
  2093.         DisposeRgn(hOldClip);
  2094.     }
  2095. }
  2096.  
  2097. ////////////////////////////////////////////////////////////////////////////////
  2098. //
  2099. //    CreateMenus
  2100. //
  2101. //    Make our menu bar. We only do about, open, and quit.
  2102. //
  2103.  
  2104. static OSErr CreateMenus()
  2105. {
  2106.     OSErr        err = noErr;
  2107.     Handle        hMenuBarResource;
  2108.     
  2109.     hMenuBarResource = GetNewMBar (kMenuBarResourceID);
  2110.     if (hMenuBarResource != nil)
  2111.     {
  2112.         SetMenuBar (hMenuBarResource);
  2113.         DisposeHandle (hMenuBarResource);
  2114.         AppendResMenu (GetMenuHandle (kAppleMenuID), 'DRVR');
  2115.         DrawMenuBar ();
  2116.     } else
  2117.         err = resNotFound;
  2118.  
  2119.     return err;
  2120. }
  2121.  
  2122.  
  2123. ////////////////////////////////////////////////////////////////////////////////
  2124. //
  2125. //    HandleCloseWindow
  2126. //
  2127. //    Disposes of a window and its refcon memory.
  2128. //
  2129.  
  2130. static void HandleCloseWindow (
  2131.     WindowPtr        pWin)
  2132. {
  2133.     WindowDataPtr    pWinData;
  2134.     OpenNodePtr        pTempOpenNode;
  2135.     RecvNodePtr        pTempRecvNode;
  2136.     
  2137.     if (pWin != nil) {
  2138.         pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2139.         if (pWinData != nil) {
  2140.         
  2141.             // dispose of the receive node records
  2142.             pTempRecvNode = pWinData->pRecvNodeList;
  2143.             while (pTempRecvNode != nil)
  2144.             {
  2145.                 if (pTempRecvNode->pReplyTimer != nil)
  2146.                 {
  2147.                     if (pTempRecvNode->pReplyTimer->timerTask.tmAddr != nil)
  2148.                         DisposeRoutineDescriptor(pTempRecvNode->pReplyTimer->timerTask.tmAddr);
  2149.                     DisposePtr((Ptr) pTempRecvNode->pReplyTimer);
  2150.                 }
  2151.                     
  2152.                 pTempRecvNode = (RecvNodePtr) pTempRecvNode->pNextNode;
  2153.                 DisposePtr((Ptr) pWinData->pRecvNodeList);
  2154.                 pWinData->pRecvNodeList = pTempRecvNode;
  2155.             }
  2156.             
  2157.             // dispose of the open node records
  2158.             pTempOpenNode = pWinData->pOpenNodeList;
  2159.             while (pTempOpenNode != nil)
  2160.             {
  2161.                 CloseFWXNode(pTempOpenNode->nodeID);
  2162.                 
  2163.                 pTempOpenNode = (OpenNodePtr) pTempOpenNode->pNextNode;
  2164.                 DisposePtr((Ptr) pWinData->pOpenNodeList);
  2165.                 pWinData->pOpenNodeList = pTempOpenNode;
  2166.             }
  2167.             
  2168.             DisposePtr((Ptr) pWinData);
  2169.             DisposeWindow(pWin);
  2170.         }
  2171.     }
  2172. }
  2173.  
  2174. //////////////////////////////////////////////////////////////////////////////
  2175. //
  2176. //    HandleQuit
  2177. //
  2178. //    Quit the app
  2179. //
  2180.  
  2181. static void HandleQuit (void)
  2182. {
  2183.     SInt16            itemHit;
  2184.     
  2185.     if (gSendingFile || gCheckingTransfer) {
  2186.         // JKL *** does ok button work right? Complete and then quit
  2187.         // is background processing correct?
  2188.         itemHit = HandleCautionAlert(kCantQuitAlertID);
  2189.         if (itemHit == kCancelButton) {        // the abort and quit button
  2190.             StopTransfer(nil);
  2191.             gpFWXAppData->quitFlag = true;
  2192.         }
  2193.     } else {
  2194.         gpFWXAppData->quitFlag = true;
  2195.     }
  2196.     
  2197.     if (gpFWXAppData->quitFlag) {
  2198.         SendFWXQuit();
  2199.         if (gpFWXAppData->pNotifyRec->nmRefCon == kNotificationPosted)
  2200.             NMRemove(gpFWXAppData->pNotifyRec);
  2201.             
  2202.         if (gpFWXAppData->pSenderWindow != nil)
  2203.             HandleCloseWindow(gpFWXAppData->pSenderWindow);
  2204.         RemoveDragHandlers();
  2205.     }
  2206.  
  2207. }
  2208.  
  2209.  
  2210. //////////////////////////////////////////////////////////////////////////////
  2211. //
  2212. //    HandleMenuCommand
  2213. //
  2214. //    handle repsonses to user menu selections
  2215. //
  2216.  
  2217. static void HandleMenuCommand(
  2218.     SInt32                    menuCommand)
  2219. {
  2220.     VersRecHndl                h;
  2221.     WindowPtr                pWin;
  2222.     UInt8                    *vers;
  2223.     SInt16                    menuID;
  2224.     SInt16                    menuItem;
  2225.     Str255                    deskAccessoryName;
  2226.     
  2227.     menuID = menuCommand >> 16;
  2228.     menuItem = menuCommand & 0xFFFF;
  2229.  
  2230.     switch (menuID)
  2231.     {
  2232.         case kAppleMenuID:
  2233.             if (menuItem == kAboutMenuItem)
  2234.             {
  2235.                 h = (VersRecHndl) Get1Resource('vers', 1);
  2236.                 vers = (**h).shortVersion;
  2237.                 vers += (vers[0] + 1);
  2238.                 ParamText(vers, "\p", "\p", "\p");
  2239.                 HandleAlert(kAboutAlertResourceID);
  2240.             }
  2241.             else
  2242.             {
  2243.                 GetMenuItemText(GetMenuHandle(kAppleMenuID), menuItem, deskAccessoryName);
  2244.                 OpenDeskAcc(deskAccessoryName);
  2245.             }
  2246.             break;
  2247.  
  2248.         case kFileMenuID:
  2249.             switch (menuItem)
  2250.             {
  2251.                 case kOpenMenuItem:
  2252.                     pWin = gpFWXAppData->pSenderWindow;
  2253.                     ShowWindow(pWin);
  2254.                     EnableItem(GetMenuHandle(kFileMenuID), kCloseMenuItem);
  2255.                     DisableItem(GetMenuHandle(kFileMenuID), kOpenMenuItem);
  2256.                     EnableItem(GetMenuHandle(kViewMenuID), 0);
  2257.                     DrawMenuBar();
  2258.                     break;
  2259.                 case kCloseMenuItem:
  2260.                     pWin = gpFWXAppData->pSenderWindow;
  2261.                     HideWindow(pWin);
  2262.                     EnableItem(GetMenuHandle(kFileMenuID), kOpenMenuItem);
  2263.                     DisableItem(GetMenuHandle(kFileMenuID), kCloseMenuItem);
  2264.                     DisableItem(GetMenuHandle(kViewMenuID), 0);
  2265.                     DrawMenuBar();
  2266.                     break;
  2267.                 case kOpenDropMenuItem:
  2268.                     OpenDropFolder();
  2269.                     break;
  2270.                 case kQuitMenuItem:
  2271.                     HandleQuit();
  2272.                     break;
  2273.             }
  2274.             break;
  2275.         case kEditMenuID:
  2276.             switch (menuItem)
  2277.             {
  2278.                 case kPrefsMenuItem:
  2279.                     HandlePrefsDialog();
  2280.                     break;
  2281.             }
  2282.         case kViewMenuID:
  2283.             switch (menuItem)
  2284.             {
  2285.                 case kSmallIconMenuItem:
  2286.                 case kIconMenuItem:
  2287.                     HandleViewSize(menuItem);
  2288.                     break;
  2289.             }
  2290.             break;
  2291.     }
  2292.     HiliteMenu(0);      // unhilight menu title
  2293. }
  2294.  
  2295. //////////////////////////////////////////////////////////////////////////////
  2296. //
  2297. //    OpenDropFolder
  2298. //
  2299. //    Send an appleevent to the finder to open our drop folder
  2300. //
  2301. OSErr OpenDropFolder(void)
  2302. {
  2303.     AppleEvent                send;
  2304.     AppleEvent                reply;
  2305.     AEDesc                    target;
  2306.     ProcessSerialNumber        psn;
  2307.     ProcessInfoRecPtr        pInfo;
  2308.     SInt32                    dirID;
  2309.     OSErr                    err;
  2310.  
  2311.     psn.highLongOfPSN = kNoProcess;
  2312.     psn.lowLongOfPSN = kNoProcess;
  2313.     pInfo = (ProcessInfoRecPtr) NewPtr(sizeof(ProcessInfoRec));
  2314.     if (pInfo == nil)
  2315.         return memFullErr;
  2316.     pInfo->processInfoLength = sizeof(ProcessInfoRec);
  2317.     pInfo->processName = nil;
  2318.     pInfo->processAppSpec = nil;
  2319.     do {
  2320.         err = GetNextProcess(&psn);
  2321.         GetProcessInformation(&psn, pInfo);
  2322.     }
  2323.     while ((err == noErr) && (pInfo->processType != 'FNDR'));
  2324.     DisposePtr((Ptr) pInfo);
  2325.     
  2326.     err = FSpDirCreate(&gpFWXAppData->fwixReceiveFolder, smSystemScript, &dirID);
  2327.     if (err == dupFNErr)
  2328.         err = noErr;
  2329.         
  2330.     if (err == noErr) {
  2331.                 
  2332.         err = AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber), &target);
  2333.         if (err != noErr)
  2334.             return err;
  2335.  
  2336.         err = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &target, 
  2337.                 kAutoGenerateReturnID, kAnyTransactionID, &send);
  2338.         
  2339.         err = AEPutParamPtr(&send, keyDirectObject, typeFSS, (Ptr) &(gpFWXAppData->fwixReceiveFolder), sizeof(FSSpec));
  2340.  
  2341.         err = AESend(&send, &reply, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  2342.                     kAENormalPriority, kAEDefaultTimeout, nil, nil);
  2343.  
  2344.         AEDisposeDesc(&target);
  2345.         AEDisposeDesc(&send);
  2346.     }
  2347.     SetFrontProcess(&psn);
  2348.     
  2349.     return err;
  2350. }
  2351.  
  2352. //////////////////////////////////////////////////////////////////////////////
  2353. //
  2354. //    OpenSharingSetup
  2355. //
  2356. //    Send an appleevent to the finder to open the Sharing Setup Control Panel
  2357. //
  2358. static OSErr OpenSharingSetup(void)
  2359. {
  2360.     AppleEvent                send;
  2361.     AppleEvent                reply;
  2362.     AEDesc                    target;
  2363.     ProcessSerialNumber        psn;
  2364.     ProcessInfoRecPtr        pInfo;
  2365.     FSSpec                    spec;
  2366.     SInt32                    dirID;
  2367.     SInt16                    vRefNum;
  2368.     OSErr                    err;
  2369.  
  2370.     psn.highLongOfPSN = kNoProcess;
  2371.     psn.lowLongOfPSN = kNoProcess;
  2372.     pInfo = (ProcessInfoRecPtr) NewPtr(sizeof(ProcessInfoRec));
  2373.     if (pInfo == nil)
  2374.         return memFullErr;
  2375.     pInfo->processInfoLength = sizeof(ProcessInfoRec);
  2376.     pInfo->processName = nil;
  2377.     pInfo->processAppSpec = nil;
  2378.     do {
  2379.         err = GetNextProcess(&psn);
  2380.         GetProcessInformation(&psn, pInfo);
  2381.     }
  2382.     while ((err == noErr) && (pInfo->processType != 'FNDR'));
  2383.     DisposePtr((Ptr) pInfo);
  2384.     
  2385.     if (err == noErr) {
  2386.                 
  2387.         err = AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber), &target);
  2388.         if (err != noErr)
  2389.             return err;
  2390.  
  2391.         err = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &target, 
  2392.                 kAutoGenerateReturnID, kAnyTransactionID, &send);
  2393.         
  2394.         err = FindFolder(kOnSystemDisk, kControlPanelFolderType, kDontCreateFolder,
  2395.                         &vRefNum, &dirID);
  2396.         err = FSMakeFSSpec(vRefNum, dirID, "\pSharing Setup", &spec);
  2397.         if (err == fnfErr)
  2398.             err = FSMakeFSSpec(vRefNum, dirID, "\pFile Sharing", &spec);
  2399.         err = AEPutParamPtr(&send, keyDirectObject, typeFSS, (Ptr) &spec, sizeof(FSSpec));
  2400.  
  2401.         err = AESend(&send, &reply, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  2402.                     kAENormalPriority, kAEDefaultTimeout, nil, nil);
  2403.  
  2404.         AEDisposeDesc(&target);
  2405.         AEDisposeDesc(&send);
  2406.     }
  2407.     SetFrontProcess(&psn);
  2408.     
  2409.     return err;
  2410. }
  2411.  
  2412. ////////////////////////////////////////////////////////////////////////////////
  2413. //
  2414. //    HandleViewSize
  2415. //
  2416. //    Handle the window view size command.
  2417. //
  2418. static OSErr HandleViewSize(
  2419.     SInt16                    whichMenuItem)
  2420. {
  2421.     MenuHandle                hMenu;
  2422.     WindowPtr                pWin;
  2423.     WindowDataPtr            pWinData;
  2424.     OSErr                    err = noErr;
  2425.     
  2426.     pWin = gpFWXAppData->pSenderWindow;
  2427.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2428.     if (pWinData == nil)
  2429.         return memFullErr;
  2430.     
  2431.     hMenu = GetMenuHandle(kViewMenuID);
  2432.     if ((pWinData->windowView == kLargeIconView) && (whichMenuItem == kSmallIconMenuItem))
  2433.     {
  2434.         pWinData->windowView = kSmallIconView;
  2435.         gpFWXAppData->fwixPrefs |= kIconView;
  2436.         SetItemMark(hMenu, kSmallIconMenuItem, checkMark);
  2437.         SetItemMark(hMenu, kIconMenuItem, noMark);
  2438.         AdjustNodeIcons(pWinData, &pWin->portRect);
  2439.         AdjustScrollBars(pWin, false);
  2440.         UpdatePrefsFile();
  2441.     }
  2442.     else if ((pWinData->windowView == kSmallIconView) && (whichMenuItem == kIconMenuItem))
  2443.     {
  2444.         pWinData->windowView = kLargeIconView;
  2445.         gpFWXAppData->fwixPrefs &= ~kIconView;
  2446.         SetItemMark(hMenu, kSmallIconMenuItem, noMark);
  2447.         SetItemMark(hMenu, kIconMenuItem, checkMark);
  2448.         AdjustNodeIcons(pWinData, &pWin->portRect);
  2449.         AdjustScrollBars(pWin, false);
  2450.         UpdatePrefsFile();
  2451.     }
  2452.     InvalRect(&pWin->portRect);
  2453.     return err;    
  2454. }
  2455.  
  2456. ////////////////////////////////////////////////////////////////////////////////
  2457. //
  2458. //    HandleMouseDownEvent
  2459. //
  2460. //    This routine handles mouse down events.
  2461. //
  2462. static void HandleMouseDownEvent(
  2463.     EventRecord                    *pEventRecord)
  2464. {
  2465.     static ControlActionUPP        cupp;
  2466.     GrafPtr                        curPort;
  2467.     WindowRef                    theWindow;
  2468.     Rect                        tempRect;
  2469.     ControlHandle                hControl;
  2470.     Point                        mouse;
  2471.     SInt16                        whichPart;
  2472.     SInt16                        cntlPart;
  2473.     
  2474.     whichPart = FindWindow(pEventRecord->where, &theWindow);
  2475.     
  2476.     switch (whichPart) {
  2477.         case inSysWindow:  // desk accessory window
  2478.             SystemClick(pEventRecord, theWindow);
  2479.             break;
  2480.  
  2481.         case inMenuBar:
  2482.             HandleMenuCommand(MenuSelect(pEventRecord->where));
  2483.             break;
  2484.  
  2485.         case inDrag:
  2486.             tempRect = qd.screenBits.bounds;
  2487.             if (gpFWXAppData->pSenderWindow != FrontWindow())
  2488.             {
  2489.                 // progress bar would be up, it is movable modal
  2490.                 if (theWindow == FrontWindow())
  2491.                     DragWindow(theWindow, pEventRecord->where, &tempRect);
  2492.                 else
  2493.                     SysBeep(0);
  2494.             } else
  2495.                 DragWindow(theWindow, pEventRecord->where, &tempRect);
  2496.             SaveWindowPos(theWindow);
  2497.             break;
  2498.  
  2499.         case inGoAway:
  2500.             if (TrackGoAway(theWindow, pEventRecord->where)) {
  2501.                 HideWindow(theWindow);
  2502.                 EnableItem(GetMenuHandle(kFileMenuID), kOpenMenuItem);
  2503.                 DisableItem(GetMenuHandle(kFileMenuID), kCloseMenuItem);
  2504.                 DisableItem(GetMenuHandle(kViewMenuID), 0);
  2505.                 DrawMenuBar();
  2506.             }
  2507.             break;
  2508.  
  2509.         case inGrow:
  2510.             HandleGrowWindow(theWindow, pEventRecord->where);
  2511.             break;
  2512.             
  2513.         case inZoomIn:
  2514.         case inZoomOut:
  2515.             if (TrackBox(theWindow, pEventRecord->where, whichPart))
  2516.                 HandleZoomWindow(theWindow, whichPart);
  2517.             break;
  2518.  
  2519.         case inContent:
  2520.                     GetPort(&curPort);
  2521.                     SetPort(theWindow);
  2522.                     mouse = pEventRecord->where;
  2523.                     GlobalToLocal(&mouse);
  2524.                     cntlPart = FindControl(mouse, theWindow, &hControl);    
  2525.             if (cntlPart)
  2526.             {
  2527.                 if (gpFWXAppData->pSenderWindow == FrontWindow())
  2528.                 {
  2529.                     // handle user click in one of the sender window scroll bars
  2530.                     if (cntlPart == kControlIndicatorPart)
  2531.                         HandleThumbScroll(hControl, theWindow, mouse);
  2532.                     else
  2533.                     {
  2534.                         if (!cupp)
  2535.                             cupp = NewControlActionProc(HandleScrollAction);
  2536.                         TrackControl(hControl, mouse, cupp);
  2537.                     }
  2538.                 }
  2539.                 else
  2540.                 {    // progress bar is up, make it modal, check for stop button
  2541.                     if (theWindow != FrontWindow())
  2542.                         SysBeep(0);
  2543.                     else
  2544.                     {
  2545.                         if (cntlPart == kControlButtonPart)
  2546.                         {
  2547.                             if (TrackControl(hControl, mouse, nil))
  2548.                                 StopTransfer(nil);
  2549.                         }
  2550.                     }
  2551.                 }
  2552.             }
  2553.             SetPort(curPort);
  2554.             break;
  2555.     }
  2556. }
  2557.  
  2558. ////////////////////////////////////////////////////////////////////////////////
  2559. //
  2560. //    HandleThumbScroll
  2561. //
  2562. //    Handle scrolling by the thumb button.
  2563. //
  2564. static pascal void HandleThumbScroll (
  2565.     ControlHandle        scrollCtl,
  2566.     WindowPtr            pWin,
  2567.     Point                mouse)
  2568. {
  2569.     WindowDataPtr        pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2570.     RgnHandle            updateRgn;
  2571.     Rect                drawRect;
  2572.     SInt16                value, h, v;
  2573.     SInt16                cntlPart;
  2574.     
  2575.     value = GetControlValue(scrollCtl);
  2576.     cntlPart = TrackControl(scrollCtl, mouse, nil);
  2577.     if (cntlPart)
  2578.     {
  2579.         value -= GetControlValue(scrollCtl);
  2580.         if (value != 0)
  2581.         {
  2582.             h = v = 0;
  2583.             if (scrollCtl == pWinData->hVScrollBar)
  2584.                 v = value;
  2585.             else
  2586.                 h = value;
  2587.                 
  2588.             drawRect = pWin->portRect;
  2589.             drawRect.bottom -= kScrollBarAdjust;
  2590.             drawRect.right -= kScrollBarAdjust;
  2591.             ScrollRect(&drawRect, h, v, updateRgn = NewRgn());
  2592.             InvalRgn(updateRgn);
  2593.             DisposeRgn(updateRgn);
  2594.             BeginUpdate(pWin);
  2595.             DrawWindow(pWin);
  2596.             EndUpdate(pWin);
  2597.         }
  2598.     }
  2599. }
  2600.  
  2601. ////////////////////////////////////////////////////////////////////////////////
  2602. //
  2603. //    HandleScrollAction
  2604. //
  2605. //    Handle scrolling window.
  2606. //
  2607. static pascal void HandleScrollAction (
  2608.     ControlHandle        scrollCtl,
  2609.     SInt16                part)
  2610. {
  2611.     WindowPtr            pWin = gpFWXAppData->pSenderWindow;
  2612.     WindowDataPtr        pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2613.     RgnHandle            updateRgn;
  2614.     Rect                drawRect;
  2615.     SInt16                delta, value, h, v;
  2616.     SInt16                oldValue, max;
  2617.  
  2618.     if ((pWinData != nil) && part)
  2619.     {
  2620.         switch (part)
  2621.         {
  2622.             case kControlUpButtonPart:
  2623.             case kControlDownButtonPart:
  2624.                 delta = 5;
  2625.                 break;
  2626.  
  2627.             case kControlPageUpPart:
  2628.             case kControlPageDownPart:
  2629.                 if (scrollCtl == pWinData->hHScrollBar)
  2630.                     delta = pWin->portRect.right - pWin->portRect.left - kScrollBarAdjust;
  2631.                 else
  2632.                     delta = pWin->portRect.bottom - pWin->portRect.top - kScrollBarAdjust;                    
  2633.                 break;
  2634.             
  2635.             // handle cases generated by keyboard input
  2636.             case kPageUpKey:
  2637.             case kPageDownKey:
  2638.                 delta = pWin->portRect.bottom - pWin->portRect.top - kScrollBarAdjust;
  2639.                 break;
  2640.             
  2641.             case kHomeKey:
  2642.                 delta = -32000;        // a large enough number to make value = 0
  2643.                 break;
  2644.             
  2645.             case kEndKey:
  2646.                 delta = 32000;        // a large enough number to make value = max
  2647.                 break;
  2648.         }
  2649.  
  2650.         // reverse direction for scrolling up
  2651.         if ((part == kControlUpButtonPart) || (part == kControlPageUpPart) || (part == kPageUpKey))
  2652.             delta = -delta;
  2653.  
  2654.         // pin scroll value at min or max.
  2655.         oldValue = GetControlValue(scrollCtl);
  2656.         value = oldValue + delta;
  2657.         if (value < 0)
  2658.             value = 0;
  2659.         max = GetControlMaximum(scrollCtl);
  2660.         if (value > max)
  2661.             value = max;
  2662.  
  2663.         if (value != oldValue)
  2664.         {
  2665.             drawRect = pWin->portRect;
  2666.             drawRect.bottom -= kScrollBarAdjust;
  2667.             drawRect.right -= kScrollBarAdjust;
  2668.             SetControlValue(scrollCtl, value);
  2669.             h = oldValue - value;
  2670.             v = 0;
  2671.             if (scrollCtl == pWinData->hVScrollBar)
  2672.             {
  2673.                 v = h;
  2674.                 h = 0;
  2675.             }
  2676.             ScrollRect(&drawRect, h, v, updateRgn = NewRgn());
  2677.             InvalRgn(updateRgn);
  2678.             DisposeRgn(updateRgn);
  2679.             BeginUpdate(pWin);
  2680.             DrawWindow(pWin);
  2681.             EndUpdate(pWin);
  2682.         }
  2683.     }
  2684. }
  2685.  
  2686. ////////////////////////////////////////////////////////////////////////////////
  2687. //
  2688. //    HandleZoomWindow
  2689. //
  2690. //    Zoom the window.
  2691. //
  2692. static void HandleZoomWindow(
  2693.     WindowPtr            pWin,
  2694.     SInt16                whichZoom)
  2695. {
  2696.     WindowDataPtr        pWinData;
  2697.     Rect                zoomRect;
  2698.     SInt16                vSize, hSize;
  2699.     SInt16                row, column;
  2700.  
  2701.     if (whichZoom == inZoomOut)
  2702.     {
  2703.         pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2704.         if (pWinData != nil)
  2705.         {
  2706.             if (pWinData->windowView == kLargeIconView)
  2707.             {
  2708.                 row = pWinData->numRecvNodes % kLargeRowCount;
  2709.                 column = pWinData->numRecvNodes / kLargeRowCount;
  2710.                 if (column == 0)
  2711.                     vSize = row * kLargeVSize;
  2712.                 else
  2713.                     vSize = kLargeRowCount * kLargeVSize;
  2714.                 hSize = (column + 1) * kLargeHSize;
  2715.             }
  2716.             else
  2717.             {    
  2718.                 row = pWinData->numRecvNodes % kSmallRowCount;
  2719.                 column = pWinData->numRecvNodes / kSmallRowCount;
  2720.                 if (column == 0)
  2721.                     vSize = row * kSmallVSize;
  2722.                 else
  2723.                     vSize = kSmallRowCount * kSmallVSize;
  2724.                 // make sure there is enough room for scroll bars
  2725.                 if (vSize < kLargeVSize)
  2726.                     vSize = kLargeVSize;
  2727.                 hSize = (column + 1) * kSmallHSize;
  2728.             }
  2729.         }
  2730.         zoomRect = (**((WStateDataHandle) ((WindowPeek) pWin)->dataHandle)).userState;
  2731.         zoomRect.bottom = zoomRect.top + vSize + kScrollBarWidth;
  2732.         zoomRect.right = zoomRect.left + hSize + kScrollBarWidth;
  2733.         (**((WStateDataHandle) ((WindowPeek) pWin)->dataHandle)).stdState = zoomRect;
  2734.     }
  2735.     ZoomWindow(pWin, whichZoom, FrontWindow() == pWin);
  2736.     AdjustScrollBars(pWin, true);
  2737.     InvalRect(&pWin->portRect);
  2738.     SaveWindowPos(pWin);
  2739. }
  2740.  
  2741. ////////////////////////////////////////////////////////////////////////////////
  2742. //
  2743. //    HandleGrowWindow
  2744. //
  2745. //    Grow the window.
  2746. //
  2747. static void HandleGrowWindow(
  2748.     WindowPtr            pWin,
  2749.     Point                clickLoc)
  2750. {
  2751.     Rect                limitRect;
  2752.     SInt32                growSize;
  2753.     
  2754.     SetRect(&limitRect, kLargeVSize, kLargeVSize, 3000, 3000);
  2755.     growSize = GrowWindow(pWin, clickLoc, &limitRect);
  2756.     if (growSize != 0)
  2757.     {
  2758.         SizeWindow(pWin, LoWord(growSize), HiWord(growSize), true);
  2759.         AdjustScrollBars(pWin, true);
  2760.         InvalRect(&pWin->portRect);
  2761.         SaveWindowPos(pWin);
  2762.     }
  2763. }
  2764.  
  2765. ////////////////////////////////////////////////////////////////////////////////
  2766. //
  2767. //    StopTransfer
  2768. //
  2769. //    Handle user stopping file transfer.
  2770. //
  2771. void StopTransfer (
  2772.     RecvNodePtr                    pNode)
  2773. {
  2774.     FWXPacketPtr                pPktInfo;        // puts a packet structure on ioBuffer
  2775.     IOParamPtr                    pIOPb;            // write parameter block
  2776.     TxFSSpecPtr                    pTxItem;
  2777.     NodeSendItemPtr                pSendItem, pTempItem;
  2778.     
  2779.     if (pNode != nil)
  2780.     {
  2781.         if (pNode->pTxItemList != nil)
  2782.         {
  2783.             pSendItem = pNode->pTxItemList;
  2784.             while (pSendItem != nil)
  2785.             {
  2786.                 pTempItem = pSendItem;
  2787.                 pSendItem = pSendItem->pNextSendItem;
  2788.                 DisposePtr((Ptr) pTempItem);
  2789.             }
  2790.             pNode->pTxItemList = nil;
  2791.         }
  2792.     }
  2793.             
  2794.     if (gSendingFile || gCheckingTransfer)
  2795.     {
  2796.         gCheckingTransfer = false;
  2797.     gForkComplete = true;
  2798.     gForkWriteComplete = true;
  2799.     CleanupCopyDialog(FrontWindow());
  2800.     if (gSendingDataFork || gSendingResFork)
  2801.     {
  2802.         gSendingDataFork = false;
  2803.         gSendingResFork = false;
  2804.         FSClose(gCurForkRefNum);
  2805.     }
  2806.     
  2807.         if (gSendingFile)
  2808.         {
  2809.             gSendingFile = false;
  2810.             
  2811.     // send file stopped to receiver
  2812.     FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  2813.     if (pIOPb != nil)
  2814.     {
  2815.         SetupFWControlPB(pIOPb);
  2816.                 
  2817.         pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  2818.         pPktInfo->packetType = kTransferStopped;
  2819.         pIOPb->ioMisc = (Ptr) kTransferStopped;
  2820.         pIOPb->ioReqCount = 4;                // just packet header
  2821.  
  2822.         CallFWXNode(pIOPb);
  2823.     }
  2824.     }
  2825.     }
  2826.  
  2827.     // dequeue and dispose of all file queue entries
  2828.     pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  2829.     while (pTxItem != nil)
  2830.     {
  2831.         Dequeue((QElemPtr) pTxItem, &gSendQHdr);
  2832.         DisposePtr((Ptr) pTxItem->pFSSpec);
  2833.         DisposePtr((Ptr) pTxItem);
  2834.  
  2835.         // get another queue item
  2836.         pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  2837.     }
  2838. }
  2839.  
  2840. ////////////////////////////////////////////////////////////////////////////////
  2841. //
  2842. //    HandleUpdateEvent
  2843. //
  2844. //    This routine handles update events.
  2845. //
  2846. void HandleUpdateEvent (
  2847.     EventRecord            *pEventRecord)
  2848. {
  2849.     WindowPtr            pWin;
  2850.     GrafPtr                curPort;
  2851.  
  2852.     pWin = (WindowPtr) pEventRecord->message;
  2853.  
  2854.     GetPort(&curPort);
  2855.     SetPort(pWin);
  2856.     if (pWin == gpFWXAppData->pSenderWindow)
  2857.     {
  2858.         BeginUpdate(pWin);        
  2859.             DrawWindow(pWin);
  2860.         EndUpdate(pWin);
  2861.     }
  2862.     else
  2863.     {
  2864.         BeginUpdate(pWin);
  2865.         UpdateDialog(pWin, pWin->visRgn);
  2866.         EndUpdate(pWin);
  2867.     }
  2868.     SetPort(curPort);
  2869. }
  2870.  
  2871. ////////////////////////////////////////////////////////////////////////////////
  2872. //
  2873. //    HandleKeyEvent
  2874. //
  2875. //    This routine handles key events. The only ones we handle are menu shortcuts
  2876. //    and stopping the transfer shortcuts.
  2877. //
  2878. static void HandleKeyEvent (
  2879.     EventRecord            *pEventRecord)
  2880. {
  2881.     WindowPtr            pWin;
  2882.     WindowDataPtr        pWinData;
  2883.     char                key;
  2884.     
  2885.     key = pEventRecord->message & charCodeMask;
  2886.  
  2887.     if ((pEventRecord->modifiers & cmdKey) && (pEventRecord->what == keyDown))
  2888.     {
  2889.         if ((gSendingFile || gCheckingTransfer) && (key == kPeriodKey))
  2890.             StopTransfer(nil);
  2891.         else
  2892.             HandleMenuCommand(MenuKey(key));
  2893.     }
  2894.     
  2895.     if ((gSendingFile || gCheckingTransfer) && (key == kEscapeKey))
  2896.         StopTransfer(nil);
  2897.     
  2898.     if ((key == kPageUpKey) || (key == kPageDownKey) || (key == kHomeKey) || (key == kEndKey))
  2899.     {
  2900.         pWin = FrontWindow();
  2901.         if (pWin == gpFWXAppData->pSenderWindow)
  2902.         {
  2903.             pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2904.             HandleScrollAction(pWinData->hVScrollBar, key);
  2905.         }
  2906.     }
  2907. }
  2908.  
  2909. ////////////////////////////////////////////////////////////////////////////////
  2910. //
  2911. // HandleOSEvent
  2912. //
  2913. // This routine handles OS events.
  2914. //
  2915.  
  2916. static void HandleOSEvent(
  2917.     EventRecord            *pEventRecord)
  2918. {
  2919.     UInt32                osEventType;
  2920.  
  2921.     // Get the OS event type.
  2922.     osEventType = pEventRecord->message >> 24;
  2923.  
  2924.     switch (osEventType)
  2925.     {
  2926.         case suspendResumeMessage:
  2927.             if (pEventRecord->message & resumeFlag)
  2928.             {
  2929.                 gpFWXAppData->inForeground = true;
  2930.  
  2931.                 if (gpFWXAppData->pNotifyRec->nmRefCon == kNotificationPosted)
  2932.                 {
  2933.                     NMRemove(gpFWXAppData->pNotifyRec);
  2934.                     gpFWXAppData->pNotifyRec->nmRefCon = kNoNotificationPosted;
  2935.                 }
  2936.             }
  2937.             else
  2938.                 gpFWXAppData->inForeground = false;
  2939.             
  2940.             HandleActivate(FrontWindow(), gpFWXAppData->inForeground);
  2941.             break;
  2942.     }
  2943. }
  2944.  
  2945.  
  2946. //////////////////////////////////////////////////////////////////////////////
  2947. //
  2948. //    HandleEvent
  2949. //
  2950. //    main event handling routine
  2951. //
  2952.  
  2953. static void HandleEvent (
  2954.     EventRecord        *theEvent)
  2955. {
  2956.     Point            point;
  2957.  
  2958.     switch (theEvent->what) {
  2959.         case mouseDown:
  2960.             HandleMouseDownEvent(theEvent);
  2961.             break;
  2962.  
  2963.         case updateEvt:
  2964.             HandleUpdateEvent(theEvent);
  2965.             break;
  2966.                     
  2967.         case keyDown:
  2968.         case autoKey:
  2969.             HandleKeyEvent(theEvent);
  2970.             break;
  2971.             
  2972.         case kHighLevelEvent:
  2973.             AEProcessAppleEvent(theEvent);
  2974.             break;
  2975.                     
  2976.         case osEvt:
  2977.             HandleOSEvent(theEvent);
  2978.             break;
  2979.             
  2980.         case diskEvt:
  2981.             if ((theEvent->message >> 16) != noErr) {
  2982.                 SetPt (&point, kDILeft, kDITop);
  2983.                 DIBadMount (point, theEvent->message);
  2984.             }
  2985.             break;
  2986.  
  2987.         case activateEvt:
  2988.             HandleActivate((WindowPtr) theEvent->message, (theEvent->modifiers & activeFlag) != 0);
  2989.             break;
  2990.     }
  2991. }
  2992.  
  2993. //////////////////////////////////////////////////////////////////////////////
  2994. //
  2995. //    HandleActivate
  2996. //
  2997. //    Take care of activating/deactivating, mainly just handling controls
  2998. //    and grow box.
  2999. //
  3000. static void HandleActivate(
  3001.     WindowPtr                pWin,
  3002.     Boolean                    becomingActive)
  3003. {
  3004.     WindowDataPtr            pWinData;
  3005.     
  3006.     if (IsAppWindow(pWin))
  3007.     {
  3008.         if (becomingActive)
  3009.         {
  3010.             gpFWXAppData->inForeground = true;
  3011.             if (pWin == gpFWXAppData->pSenderWindow)
  3012.             {
  3013.                 pWinData = (WindowDataPtr) GetWRefCon(pWin);
  3014.                 ShowControl(pWinData->hHScrollBar);
  3015.                 ShowControl(pWinData->hVScrollBar);
  3016.             }
  3017.             InvalRect(&pWin->portRect);
  3018.         }
  3019.         else
  3020.         {
  3021.             gpFWXAppData->inForeground = false;
  3022.             if (pWin == gpFWXAppData->pSenderWindow)
  3023.             {
  3024.                 pWinData = (WindowDataPtr) GetWRefCon(pWin);
  3025.                 HideControl(pWinData->hHScrollBar);
  3026.                 HideControl(pWinData->hVScrollBar);
  3027.                 DrawGrowIcon(pWin);
  3028.             }
  3029.         }
  3030.     }
  3031. }
  3032.  
  3033. //////////////////////////////////////////////////////////////////////////////
  3034. //
  3035. //    IsAppWindow
  3036. //
  3037. //    Check to see if our window needs handling for activate event.
  3038. //
  3039. static Boolean IsAppWindow(
  3040.     WindowPtr                pWin)
  3041. {
  3042.     SInt16                    windowKind;
  3043.  
  3044.     if (pWin == nil)
  3045.         return false;
  3046.     else {
  3047.         windowKind = ((WindowPeek) pWin)->windowKind;
  3048.         return (windowKind == userKind);
  3049.     }
  3050. }
  3051.  
  3052. //////////////////////////////////////////////////////////////////////////////
  3053. //
  3054. //    HandleIdle
  3055. //
  3056. //    At idle time check for processing send/receive information that may be
  3057. //    halted.
  3058. //
  3059. void HandleIdle(void)
  3060. {
  3061.     RecvNodePtr                pRecvNode;
  3062.     CurFileInfoPtr            pTxInfo;
  3063.     OSErr                    err;
  3064.     
  3065.     // received some data, handle it
  3066.     if (gReceiveQHdr.qHead != nil) {
  3067.         HandleReceive();
  3068.     }
  3069.     
  3070.     if (gSendingFile)
  3071.         UpdateProgressBar(FrontWindow(), kProgressBarUserItem);
  3072.     
  3073.     // if a file is being sent and end of file has been read, handle it
  3074.     if (gSendingDataFork || gSendingResFork)
  3075.     {
  3076.         if (gForkComplete && gForkWriteComplete)
  3077.         {
  3078.             HandleForkReadComplete();
  3079.         }
  3080.     }
  3081.  
  3082.     // if sending errors, show the alert and other routines
  3083.     // will take care of the clean up
  3084.     // JKL *** you sure about this?, no!
  3085.     if (gSendError != 0) {
  3086.         gSendError = (FWXNodeID) 0;
  3087.         err = GetNodeInfo(gSendError, &pRecvNode);
  3088.         if (err == noErr) {
  3089.             ParamText(pRecvNode->nodeName, "\p","\p","\p");
  3090.             HandleCautionAlert(kCommunicationErrorAlertID);
  3091.         }
  3092.     }
  3093.     
  3094.     // if receiving error show the alert and also clean up
  3095.     // pending receive
  3096.     if (gReceiveError != 0) {
  3097.         gReceiveError = (FWXNodeID) 0;
  3098.         err = GetCurFileInfo(gReceiveError, &pTxInfo, false);
  3099.         if (err == noErr)
  3100.             HandleStopTransfer(pTxInfo);
  3101.         err = GetNodeInfo(gSendError, &pRecvNode);
  3102.         if (err == noErr) {
  3103.             ParamText(pRecvNode->nodeName, "\p","\p","\p");
  3104.             HandleCautionAlert(kCommunicationErrorAlertID);
  3105.         }
  3106.     }
  3107. }
  3108.  
  3109. //////////////////////////////////////////////////////////////////////////////
  3110. //
  3111. //    HandleCautionAlert
  3112. //
  3113. //    Routine to call caution alerts
  3114. //
  3115. SInt16 HandleCautionAlert (
  3116.     SInt16                alertResID)
  3117. {
  3118.     UniversalProcPtr    alertFilterProc = NewModalFilterProc(HandleAlertEventFilter);
  3119.     SInt16                itemHit;
  3120.  
  3121.     itemHit = CautionAlert(alertResID, alertFilterProc);
  3122.     DisposeRoutineDescriptor(alertFilterProc);
  3123.     return itemHit;
  3124. }
  3125.  
  3126. //////////////////////////////////////////////////////////////////////////////
  3127. //
  3128. //    HandleStopAlert
  3129. //
  3130. //    Routine to call stop alerts
  3131. //
  3132. SInt16 HandleStopAlert (
  3133.     SInt16                alertResID)
  3134. {
  3135.     UniversalProcPtr    alertFilterProc = NewModalFilterProc(HandleAlertEventFilter);
  3136.     SInt16                itemHit;
  3137.  
  3138.     itemHit = StopAlert(alertResID, alertFilterProc);
  3139.     DisposeRoutineDescriptor(alertFilterProc);
  3140.     return itemHit;
  3141. }
  3142.  
  3143. //////////////////////////////////////////////////////////////////////////////
  3144. //
  3145. //    HandleNoteAlert
  3146. //
  3147. //    Routine to call note alerts
  3148. //
  3149. SInt16 HandleNoteAlert (
  3150.     SInt16                alertResID)
  3151. {
  3152.     UniversalProcPtr    alertFilterProc = NewModalFilterProc(HandleAlertEventFilter);
  3153.     SInt16                itemHit;
  3154.  
  3155.     itemHit = NoteAlert(alertResID, alertFilterProc);
  3156.     DisposeRoutineDescriptor(alertFilterProc);
  3157.     return itemHit;
  3158. }
  3159.  
  3160. //////////////////////////////////////////////////////////////////////////////
  3161. //
  3162. //    HandleAlert
  3163. //
  3164. //    Routine to call alerts
  3165. //
  3166. SInt16 HandleAlert (
  3167.     SInt16                alertResID)
  3168. {
  3169.     UniversalProcPtr    alertFilterProc = NewModalFilterProc(HandleAlertEventFilter);
  3170.     SInt16                itemHit;
  3171.  
  3172.     itemHit = Alert(alertResID, alertFilterProc);
  3173.     DisposeRoutineDescriptor(alertFilterProc);
  3174.     return itemHit;
  3175. }
  3176.  
  3177. //////////////////////////////////////////////////////////////////////////////
  3178. //
  3179. //    HandleAlertEventFilter
  3180. //
  3181. //    Handles alert filter events
  3182. //
  3183. static pascal Boolean HandleAlertEventFilter(
  3184.     DialogPtr            pDlog,
  3185.     EventRecord            *pEvent,
  3186.     SInt16                *itemHit)
  3187. {
  3188.     Handle                item;
  3189.     Rect                box;
  3190.     UInt32                finalTicks;
  3191.     SInt16                itemType;
  3192.     UInt8                key;
  3193.     Boolean                handledIt;
  3194.     
  3195.     handledIt = false;
  3196.     
  3197.     switch (pEvent->what)
  3198.     {
  3199.         case keyDown:
  3200.             key = pEvent->message & charCodeMask;
  3201.             
  3202.             if (key == kReturnKey || key == kEnterKey)
  3203.             {
  3204.                 GetDialogItem(pDlog, kOKButton, &itemType, &item, &box);
  3205.                 HiliteControl((ControlHandle) item, kControlButtonPart);
  3206.                 Delay(8, &finalTicks);
  3207.                 HiliteControl((ControlHandle) item, 0);
  3208.                 handledIt = true;
  3209.                 *itemHit = kOKButton;
  3210.             }
  3211.             break;
  3212.         
  3213.         case nullEvent:
  3214.             HandleIdle();
  3215.             break;
  3216.         
  3217.         case updateEvt:
  3218.             HandleUpdateEvent(pEvent);
  3219.             break;
  3220.     }
  3221.     return handledIt;
  3222. }
  3223.  
  3224. //////////////////////////////////////////////////////////////////////////////
  3225. //
  3226. //    FWXMain
  3227. //
  3228. //    main routine for FWiX
  3229. //
  3230. #ifdef __MWERKS__
  3231. void main()
  3232. #else
  3233. void FWXMain()
  3234. #endif
  3235. {
  3236.     EventRecord        theEvent;
  3237.     OSErr            err = noErr;
  3238.     Boolean            gotEvent;
  3239.     
  3240.     err = FWXInit();
  3241.     
  3242.     if (err == noErr)
  3243.     {
  3244.         do
  3245.         {
  3246.             // Get any FWX events.
  3247.             GetNextFWXClientEvent (gpFWXAppData->fwxClientID);
  3248.             
  3249.             gotEvent = WaitNextEvent(everyEvent, &theEvent, 0, nil);
  3250.             
  3251.             if (gotEvent)
  3252.                 HandleEvent(&theEvent);
  3253.             else
  3254.                 HandleIdle();
  3255.             
  3256.         } while (!gpFWXAppData->quitFlag);
  3257.     }
  3258.     else if (err == memFullErr)
  3259.     {
  3260.         HandleStopAlert(kMemoryErrorAlertID);
  3261.     }
  3262.         
  3263.     FWXDispose ();
  3264. }
  3265.  
  3266. //////////////////////////////////////////////////////////////////////////////
  3267. //
  3268. //    SetupFWXNode
  3269. //
  3270. //    Register with the fam and get any currently connected nodes
  3271. //
  3272. static OSErr SetupFWXNode(void)
  3273. {
  3274.     UInt32                numFWXNodes;
  3275.     UInt32                nodeNum;
  3276.     FWXNodeID            *nodeIDList = nil;
  3277.     OSErr                err = noErr;
  3278.  
  3279.     err = RegisterFWXClientApplication(
  3280.                 &(gpFWXAppData->fwxClientID),
  3281.                 (UInt32) gpFWXAppData);
  3282.  
  3283.     // Get list of nodes.
  3284.     //zzz theoretically, new ones can be added while we're doing this.
  3285.     if (err == noErr) {
  3286.         err = GetFWXNodeList (nil, 0, &numFWXNodes);
  3287.     }
  3288.  
  3289.     if ((err == noErr) && (numFWXNodes > 0)) {
  3290.         nodeIDList = (FWXNodeID *) NewPtr(numFWXNodes * sizeof(FWXNodeID));
  3291.         if (nodeIDList != nil) {
  3292.             err = GetFWXNodeList(nodeIDList, numFWXNodes, &numFWXNodes);
  3293.         } else
  3294.             err = memFullErr;
  3295.     }
  3296.  
  3297.     if (err == noErr) {
  3298.         for (nodeNum = 0; nodeNum < numFWXNodes; nodeNum++) {
  3299.             SendDeviceAddedToSelf(nodeIDList[nodeNum]);
  3300.         }
  3301.     }
  3302.  
  3303.     if (nodeIDList != nil)
  3304.         DisposePtr((Ptr) nodeIDList);
  3305.             
  3306.     return err;
  3307. }
  3308.  
  3309.     
  3310. //////////////////////////////////////////////////////////////////////////////
  3311. //
  3312. //    SetupIOQueue
  3313. //
  3314. //    Setup the queueus. Initialize everything. Allocate buffers for reading
  3315. //    from files and writing to FireWire. The idea is to read then use the same
  3316. //    parameter block to write. The used queue is for taking a parameter block
  3317. //    and putting back on the free queue.
  3318. //
  3319. static OSErr SetupIOQueue(void)
  3320. {
  3321.     IOParamPtr                pIOPb;
  3322.     SInt16                    i;
  3323.     OSErr                    err = noErr;
  3324.     
  3325.     // init all of the queue headers
  3326.     gSendQHdr.qHead = nil;
  3327.     gSendQHdr.qTail = nil;
  3328.  
  3329.     gAESendQHdr.qHead = nil;
  3330.     gAESendQHdr.qTail = nil;
  3331.  
  3332.     gFileReadQHdr.qHead = nil;
  3333.     gFileReadQHdr.qTail = nil;
  3334.  
  3335.     gFWControlQHdr.qHead = nil;
  3336.     gFWControlQHdr.qTail = nil;
  3337.  
  3338.     gReceiveQHdr.qHead = nil;
  3339.     gReceiveQHdr.qTail = nil;
  3340.  
  3341.     gCurFileQHdr.qHead = nil;
  3342.     gCurFileQHdr.qTail = nil;
  3343.  
  3344.     queuesInitialized = true;
  3345.  
  3346.     // create file read parameter blocks and queue them on the file read queue
  3347.     for (i=0; i < kFileReadBufs; i++) {
  3348.         pIOPb = (IOParamPtr) NewPtr(sizeof(IOParam));
  3349.         if (pIOPb != nil) {
  3350.             HoldMemory ((Ptr) pIOPb, sizeof(IOParam));
  3351.         } else {
  3352.             FWDebugStr("\pOut of memory, SetupIOQ");
  3353.             err = memFullErr;
  3354.             break;
  3355.         }
  3356.                 
  3357.         // allocate data buffer        
  3358.         pIOPb->ioBuffer = NewPtr(kFileReadBufSize);
  3359.         if (pIOPb->ioBuffer != nil) {
  3360.             HoldMemory (pIOPb->ioBuffer, kFileReadBufSize);
  3361.         } else {
  3362.             UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  3363.             DisposePtr((Ptr) pIOPb);
  3364.             FWDebugStr("\pOut of memory, SetupIOQ");
  3365.             err = memFullErr;
  3366.             break;
  3367.         }
  3368.         
  3369.         Enqueue((QElemPtr) pIOPb, &gFileReadQHdr);
  3370.     }
  3371.     
  3372.     // create FW control parameter blocks and queue them on the FW control queue
  3373.     for (i=0; i < kFWControlParams; i++) {
  3374.         pIOPb = (IOParamPtr) NewPtr(sizeof(IOParam));
  3375.         if (pIOPb != nil) {
  3376.             HoldMemory ((Ptr) pIOPb, sizeof(IOParam));
  3377.         } else {
  3378.             FWDebugStr("\pOut of memory, SetupIOQ");
  3379.             err = memFullErr;
  3380.             break;
  3381.         }
  3382.                 
  3383.         pIOPb->ioBuffer = NewPtr(kFWControlParamBufferSize);
  3384.         if (pIOPb->ioBuffer != nil) {
  3385.             HoldMemory (pIOPb->ioBuffer, kFWControlParamBufferSize);
  3386.         } else {
  3387.             UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  3388.             DisposePtr((Ptr) pIOPb);
  3389.             FWDebugStr("\pOut of memory, SetupIOQ");
  3390.             err = memFullErr;
  3391.             break;
  3392.         }
  3393.         
  3394.         Enqueue((QElemPtr) pIOPb, &gFWControlQHdr);
  3395.     }
  3396.     
  3397.     return err;    
  3398. }    
  3399.  
  3400. //////////////////////////////////////////////////////////////////////////////
  3401. //
  3402. //    InitNotification
  3403. //
  3404. //    Set up our notify routine
  3405. //zzz must deallocate pNotifyRec.
  3406. //
  3407. static OSErr InitNotification (void)
  3408. {
  3409.     NMRecPtr        pNotifyRec;
  3410.     OSErr            err = noErr;
  3411.  
  3412.     pNotifyRec = (NMRecPtr) NewPtrClear(sizeof(NMRec));
  3413.     if (pNotifyRec == nil)
  3414.         err = memFullErr;
  3415.     else {
  3416.         pNotifyRec->qType = nmType;
  3417.         pNotifyRec->nmResp = NewNMProc(HandleNotifyResponse);
  3418.         pNotifyRec->nmMark = 1;
  3419.         pNotifyRec->nmRefCon = kNoNotificationPosted;
  3420.         UpdateNotification(pNotifyRec);
  3421.     }
  3422.     gpFWXAppData->pNotifyRec = pNotifyRec;
  3423.     return err;
  3424. }
  3425.     
  3426. //////////////////////////////////////////////////////////////////////////////
  3427. //
  3428. //    UpdateNotification
  3429. //
  3430. //    Setup notification parameters according to prefs
  3431. //zzz must deallocate nmStr, hRes?
  3432. //
  3433. void UpdateNotification (
  3434.     NMRecPtr            pNMRec)
  3435. {
  3436.     Handle                hRes;
  3437.     SInt16                curAttributes;
  3438.     OSErr                err;
  3439.     SInt8                notifyPrefs = gpFWXAppData->fwixPrefs;
  3440.     
  3441.     if (notifyPrefs & kNotifyFlash)
  3442.     {
  3443.         if (pNMRec->nmIcon == nil)
  3444.         {
  3445.             // get an icon to flash
  3446.             err = GetIconSuite(&hRes, kAppIconSuiteID, svAllSmallData);
  3447.             if ((err == noErr) && (hRes != nil))
  3448.             {
  3449.                 curAttributes = GetResAttrs(hRes);
  3450.                 if (curAttributes & resPurgeable)
  3451.                     HNoPurge(hRes);
  3452.                 pNMRec->nmIcon = hRes;
  3453.             }
  3454.             else
  3455.                 pNMRec->nmIcon = nil;
  3456.         }
  3457.     }
  3458.     else if (pNMRec->nmIcon != nil)
  3459.     {
  3460.         DisposeIconSuite(pNMRec->nmIcon, false);
  3461.         pNMRec->nmIcon = nil;
  3462.     }
  3463.     
  3464. /*
  3465.     *** JKl - do the dialog ourselves so we can continue processing in the background,
  3466.     *** this code uses notification manager for dialog.
  3467.     *** Need to post dialog needed message and display dialog if we are in background.
  3468.     *** HandleReceive displays the dialog once receive is complete.
  3469.     if (notifyPrefs & kNotifyAlert)
  3470.     {
  3471.         if (pNMRec->nmStr == nil)
  3472.         {
  3473.             // get an alert string
  3474.             hRes = GetResource('STR ', kNotifyString);
  3475.             pNMRec->nmStr = (StringPtr) NewPtr(**hRes + 1);
  3476.             if (pNMRec->nmStr != nil)
  3477.                 BlockMove(*hRes, pNMRec->nmStr, **hRes + 1);
  3478.             ReleaseResource(hRes);
  3479.         }
  3480.     }
  3481.     else if (pNMRec->nmStr != nil)
  3482.     {
  3483.         DisposePtr((Ptr) pNMRec->nmStr);
  3484.         pNMRec->nmStr = nil;
  3485.     }
  3486. */
  3487. /*
  3488.     *** JKL - just play the sound our selves, this code uses the notification manager to make the sound
  3489.     *** HandleReceive now plays the sound once receive is complete    
  3490.     if (notifyPrefs & kNotifySound)
  3491.     {
  3492.         if (pNMRec->nmSound == nil)
  3493.         {
  3494.             // get the sound to play
  3495.             hRes = GetNamedResource('snd ', gpFWXAppData->fwixNotifySound);
  3496.             if (hRes != nil)
  3497.             {
  3498.                 curAttributes = GetResAttrs(hRes);
  3499.                 if (curAttributes & resPurgeable)
  3500.                     HNoPurge(hRes);
  3501.                 pNMRec->nmSound = hRes;
  3502.             }
  3503.             else
  3504.                 pNMRec->nmSound = (Handle) -1;        // at least play the system alert
  3505.         }
  3506.     } else if (pNMRec->nmSound != nil) {
  3507.         ReleaseResource(pNMRec->nmSound);
  3508.         pNMRec->nmSound = nil;
  3509.     }
  3510. */
  3511. }
  3512.     
  3513. //////////////////////////////////////////////////////////////////////////////
  3514. //
  3515. //    HandleNotifyResponse
  3516. //
  3517. //    Handle notification manager response
  3518. //
  3519. pascal void HandleNotifyResponse (
  3520.     NMRecPtr            pNMRequest)
  3521. {
  3522.     if (gpFWXAppData->inForeground) {
  3523.         NMRemove(pNMRequest);
  3524.         pNMRequest->nmRefCon = kNoNotificationPosted;
  3525.     }
  3526. }
  3527.  
  3528. //////////////////////////////////////////////////////////////////////////////
  3529. //
  3530. //    FWXInit
  3531. //
  3532. //    Initialization routine for FWX
  3533. //
  3534. static OSErr FWXInit(void)
  3535. {
  3536.     Handle            hString;
  3537.     SInt16            curResFile;
  3538.     SInt16            itemHit;
  3539.     OSErr            err = noErr;
  3540.     
  3541.     // Create global data record
  3542.     gpFWXAppData = (FWXAppDataPtr)
  3543.         NewPtrClear(sizeof (FWXAppData));
  3544.     if (gpFWXAppData == nil)
  3545.         err = memFullErr;
  3546.  
  3547.     if (err == noErr) {
  3548.         gpFWXAppData->quitFlag = false;
  3549.         gpFWXAppData->inForeground = true;
  3550.         gpFWXAppData->fwxClientID = kInvalidFWXClientID;
  3551.         gpFWXAppData->pSenderWindow = nil;
  3552.         
  3553.         gCheckingTransfer = false;
  3554.         gSendingFile = false;
  3555.         gSendingDataFork = false;
  3556.         gSendingResFork = false;
  3557.         gForkComplete = true;
  3558.         gForkWriteComplete = true;
  3559.         gSendError = (FWXNodeID) 0;
  3560.         gReceiveError = (FWXNodeID) 0;
  3561.         
  3562.         InitGraf(&qd.thePort);
  3563.         InitFonts();
  3564.         InitWindows();
  3565.         InitMenus();
  3566.         TEInit();
  3567.         InitDialogs(nil);
  3568.         InitCursor();
  3569.             
  3570.         // Make sure there is a sharing setup macintosh name
  3571.         curResFile = CurResFile();
  3572.         UseResFile(kSystemResFile);
  3573.         hString = Get1Resource('STR ', kNetworkNameID);
  3574.         UseResFile(curResFile);
  3575.         if ((hString == nil) || (**hString == 0))
  3576.         {
  3577.             // no name or string is empty
  3578.             itemHit = HandleStopAlert(kNoNameAlertID);
  3579.             if (itemHit == kOKButton)
  3580.                 OpenSharingSetup();
  3581.             ExitToShell();
  3582.         }
  3583.  
  3584.         if (err == noErr)
  3585.             err = SetupIOQueue();
  3586.         if (err == noErr)
  3587.             err = InstallAppleEventHandlers();
  3588.         if (err == noErr)
  3589.             err = InstallCompletionRoutineProcs();
  3590.         if (err == noErr)
  3591.             err = CreateMenus();
  3592.         if (err == noErr)
  3593.             err = InitPrefs();
  3594.         if (err == noErr)
  3595.             err = NewSenderWindow();
  3596.         if (err == noErr)
  3597.             err = InstallDragHandlers();
  3598.         if (err == noErr)
  3599.             err = SetupFWXNode();
  3600.         if (err == noErr)
  3601.             err = InitNotification();
  3602.     }
  3603.     return err;
  3604. }            
  3605.     
  3606. //////////////////////////////////////////////////////////////////////////////
  3607. //
  3608. //    FWXDispose
  3609. //
  3610. //    Disposal routine for FWX
  3611. //
  3612. static OSErr FWXDispose(void)
  3613. {
  3614.     IOParamPtr        pIOPb;
  3615.     OSErr            err = noErr;
  3616.  
  3617.     // dispose of file write parameter blocks and write queue
  3618.     //zzz must ensure that none are still pending
  3619.  
  3620.     // dispose of FW control parameter blocks and write queue
  3621.     //zzz must ensure that none are still pending
  3622.     if (queuesInitialized) {
  3623.         pIOPb = (IOParamPtr) gFWControlQHdr.qHead;
  3624.         while (pIOPb) {
  3625.             Dequeue ((QElemPtr) pIOPb, &gFWControlQHdr);
  3626.             UnholdMemory (pIOPb->ioBuffer, kFWControlParamBufferSize);
  3627.             DisposePtr (pIOPb->ioBuffer);
  3628.             UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  3629.             DisposePtr ((Ptr) pIOPb);
  3630.  
  3631.             pIOPb = (IOParamPtr) gFWControlQHdr.qHead;
  3632.         }
  3633.     }
  3634.  
  3635.     // dispose of file read parameter blocks and write queue
  3636.     //zzz must ensure that none are still pending
  3637.     if (queuesInitialized) {
  3638.         pIOPb = (IOParamPtr) gFileReadQHdr.qHead;
  3639.         while (pIOPb) {
  3640.             Dequeue ((QElemPtr) pIOPb, &gFileReadQHdr);
  3641.             UnholdMemory (pIOPb->ioBuffer, kFileReadBufSize);
  3642.             DisposePtr (pIOPb->ioBuffer);
  3643.             UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  3644.             DisposePtr ((Ptr) pIOPb);
  3645.  
  3646.             pIOPb = (IOParamPtr) gFileReadQHdr.qHead;
  3647.         }
  3648.     }
  3649.  
  3650.     if (gpFWXAppData != nil) {
  3651.         // Unregister as a client of FWiX.
  3652.         if (gpFWXAppData->fwxClientID != (FWXClientID) kInvalidFWXClientID)
  3653.             UnregisterFWXClientApplication (gpFWXAppData->fwxClientID);
  3654.  
  3655.         // Deallocate our globals.
  3656.         DisposePtr ((Ptr) gpFWXAppData);
  3657.         gpFWXAppData = nil;
  3658.     }
  3659.  
  3660.     return err;    
  3661. }
  3662.